【解題報告】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;
}

(其它題目略)

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