【解题报告】Codeforces Round #365 (Div. 2)

题目链接


A. Mishka and Game(Codeforces 703A)

思路

用两个变量统计两个人各胜了多少局,根据不同的的比较结果输出不同的答案即可。

代码

#include <bits/stdc++.h>
using namespace std;

int n, m, c, M, C;

int main() {
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        scanf("%d%d", &m, &c);
        if(m > c) {
            M++;
        }
        if(c > m) {
            C++;
        }
    }
    if(M == C) {
        puts("Friendship is magic!^^");
    }
    else {
        puts(M > C ? "Mishka" : "Chris");
    }
    return 0;
}

B. Mishka and trip(Codeforces 703B)

思路

首先将 12...n1 这个环路对答案的贡献算出来。然后对于每个首都,它与所有城市相连对答案的贡献等于它的魅力值乘其它所有城市的魅力值之和。但是如果对每个首都都这样算的话会产生重复。例如,对于首都 c ,它同 c1,c+1 之间的联系已经被计算过了。另外,首都与首都之间的联系可能被计算不止一次(相邻的首都之间的联系被计算了 3 次,不相邻的首都之间的联系被计算了 2 次)。
我们可以用直接法或间接法来处理这个重复。对于直接法,我们可以在遍历首都的同时维护已经处理过的首都的集合 s 和已经处理过的首都的魅力值之和 tmp ,有了这些信息就能够去除重复。(下面的代码用的是直接法)对于间接法,我们可以根据每条边的重复次数减去相应的贡献。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e5 + 10;
int n, k, L, R, M;
ll oth, sum, ans, tmp, c[maxn];
set <int> s;

int main() {
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i++) {
        scanf("%I64d", &c[i]);
        sum += c[i];
        if(i > 1) {
            ans += c[i] * c[i-1];
        }
    }
    ans += c[1] * c[n];
    while(k--) {
        scanf("%d", &M);
        L = M == 1 ? n : M - 1;
        R = M == n ? 1 : M + 1;
        oth = sum - c[M] - tmp;
        if(!s.count(L)) {
            oth -= c[L];
        }
        if(!s.count(R)) {
            oth -= c[R];
        }
        ans += c[M] * oth;
        tmp += c[M];
        s.insert(M);
    }
    printf("%I64d\n", ans);
    return 0;
}

C. Chris and Road(Codeforces 703C)

思路

这道题看似十分复杂,但是巧妙地将问题转化就能够以非常优雅的方法顺利解决。我们可以在时间确定的情况下以凸多边形为参考系,将 v 反向为 v 然后与 u⃗  合成为 U⃗  ,通过判断多边形是否在 U⃗  的一侧来判断行人是否能通过凸多边形。既然可以在时间确定的情况下判断行人是否能通过凸多边形,那么就可以通过二分查找的方式查找出最短的时间。另外,判断凸多边形的方法是遍历凸多边形的点,通过叉积判断点是否在向量的某侧。

代码

#include <bits/stdc++.h>
using namespace std;

struct Point {
    double x, y;
    Point() {}
    Point(double x, double y): x(x), y(y) {}
    void input() {
        scanf("%lf%lf", &x, &y);
    }
    friend Point operator + (const Point& a, const Point& b) {
        return Point(a.x + b.x, a.y + b.y);
    }
};

const int maxn = 1e4 + 5;
const double eps = 1e-10;
int n;
double w, v, u, l, r, mid;
Point A, B, ps[maxn];

int cmp(double x) {
    return x < -eps ? -1 : x > eps;
}

// 计算叉积
double det(Point a, Point b) {
    return a.x * b.y - b.x * a.y;
}

// 判断是否能够直接通过
bool passDirectly() {
    for(int i = 1; i <= n; i++) {
        if(cmp(det(A, ps[i])) > 0) {
            return false;
        }
    }
    return true;
}

// 判断在时刻t的时候是否能够通过
bool ok(double t) {
    for(int i = 1; i <= n; i++) {
        B = ps[i] + Point(-v * t, 0);
        if(cmp(det(A, B)) < 0) {
            return false;
        }
    }
    return true;
}

int main() {
    scanf("%d%lf%lf%lf", &n, &w, &v, &u);
    A = Point(v, u);
    for(int i = 1; i <= n; i++) {
        ps[i].input();
    }
    if(passDirectly()) {
        printf("%.10f\n", 1.0 * w / u);
        return 0;
    }
    l = 0;
    r = 2e9;
    // 二分查找
    for(int i = 0; i < 100; i++) {
        mid = (l + r) / 2;
        ok(mid) ? r = mid : l = mid;
    }
    printf("%.10f\n", 1.0 * w / u + r);
    return 0;
}

D. Mishka and Interesting sum(Codeforces 703D)

思路

由题目的“出现偶数次的数”,应该联想到出现偶数次的数的异或和为 0 ,另外出现奇数次的数的异或和为这些数每种数只出现一次时的异或和。根据异或和的性质,若能知道区间 [l,r] 内所有数的异或和 x ,和 [l,r] 内所有数每种数只出现一次的异或和y,那么对区间 [l,r] 的询问的答案就是 xy 。因为异或和具有可加性,所以 x 可以在预处理出“前缀异或和”的情况下在 O(1) 的时间内求出。另外y也可以通过树状数组在 O(log(n)) 的时间内求得(仿照 LightOj1188 的求区间内数的种类数的方法)。

代码

#include <bits/stdc++.h>
using namespace std;

#define lowbit(x) (x & -x)

struct query {
    int l, r, idx;
    query() {}
    query(int l, int r, int idx): l(l), r(r), idx(idx) {}
    bool operator < (const query& o) const {
        return r < o.r;
    }
};

const int maxn = 1e6 + 10, maxm = 1e6 + 10;
int n, m, l, r, idx, cur, a[maxn], c[maxn], xorSum[maxn], ans[maxm];
query qs[maxm];
map <int, int> mp;

void add(int p, int x) {
    for(; p <= n; p += lowbit(p)) {
        c[p] ^= x;
    }
}

int sum(int p) {
    int res = 0;
    for(; p > 0; p -= lowbit(p)) {
        res ^= c[p];
    }
    return res;
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        xorSum[i] = a[i] ^ xorSum[i-1];
    }
    scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        scanf("%d%d", &l, &r);
        qs[i] = query(l, r, i);
    }
    sort(qs + 1, qs + m + 1);
    cur = 1;
    for(int i = 1; i <= m; i++) {
        l = qs[i].l;
        r = qs[i].r;
        idx = qs[i].idx;
        for(; cur <= r; cur++) {
            if(mp[a[cur]] > 0) {
                add(mp[a[cur]], a[cur]);
            }
            add(cur, a[cur]);
            mp[a[cur]] = cur;
        }
        ans[idx] = xorSum[r] ^ xorSum[l - 1] ^ sum(r) ^ sum(l - 1);
    }
    for(int i = 1; i <= m; i++) {
        printf("%d\n", ans[i]);
    }
    return 0;
}

(其它题目略)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章