【题录】2016年中国大学生程序设计竞赛(合肥)

1.传递

暴力;

3.朋友

注意到最后一个进行的操作中与根节点直接相连的边权值必然是由1变0。而如果一条边原本的权值为1,则这条边的权值若要变为0则子树内的操作次数为奇数次,反之则为偶数次。由此可以发现先手与后手的胜负条件即为与根节点直接相连的边中权值为1的边的数目的奇偶性。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
int n, m, num[maxn];
map <pair<int, int>, int> M;

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

int main() {
    int T = read();
    while(T --) {
        n = read(), m = read();
        for(int i = 1; i <= n; i ++) num[i] = 0;
        for(int i = 1; i < n; i ++) {
            int x = read(), y = read(), z = read();
            if(x > y) swap(x, y);
            if(z) num[x] ++ , num[y] ++;
            M[make_pair(x, y)] = z;
        }
        for(int i = 1; i <= m; i ++) {
            int opt = read();
            if(!opt) {
                int x = read();
                if(num[x] & 1) printf("Girls win!
");
                else printf("Boys win!
");
            }
            else {
                int x = read(), y = read(), z = read();
                if(x > y) swap(x, y);
                if(z != M[make_pair(x, y)]) {
                    if(!z) num[x] --, num[y] --;
                    else num[x] ++, num[y] ++;
                    M[make_pair(x, y)] = z;
                }
            }
        }
    }
    return 0;
}

5.扫雷

dp[i][a][b][c][d] 表示 dp 到第 i 列,左上角,上方,右下角,下方的格子中的地雷数目分别为 a,b,c,d 的方案数。

#include <bits/stdc++.h>
using namespace std;
#define maxn 10005
#define mod 100000007
int A[maxn], f[maxn][2][2][2][2];
char s[maxn];

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

void Up(int &x, int y) {
    x += y; if(x >= mod) x -= mod;
}

void trans(int i, int a, int b, int c, int d) {
    int now = A[i] - (a + b + c + d);
    if(now < 0) return;
    for(int x = 0; x <= 1; x ++)
        for(int y = 0; y <= 1; y ++) 
            if((x + y) == now) 
                Up(f[i + 1][b][x][d][y], f[i][a][b][c][d]);
}

int main() {
    int T = read();
    while(T --) {
        scanf("%s", s + 1); int n = strlen(s + 1), ans = 0;
        for(int i = 1; i <= n; i ++) A[i] = s[i] - '0';
        if(n == 1) {
            if(A[1] == 0 || A[1] == 2) printf("1
");
            else if(A[1] == 1) printf("2
");
            else printf("0
");
            continue;
        }
        for(int i = 1; i <= n; i ++)
            for(int x = 0; x <= 1; x ++)
                for(int y = 0; y <= 1; y ++)
                    for(int t = 0; t <= 1; t ++)
                        for(int m = 0; m <= 1; m ++)
                            f[i][x][y][t][m] = 0;
        for(int x = 0; x <= 1; x ++)
            for(int y = 0; y <= 1; y ++)
                for(int t = 0; t <= 1; t ++)
                    for(int m = 0; m <= 1; m ++)
                        if(x + y + t + m == A[1])
                            f[2][x][y][t][m] = 1;
        for(int i = 2; i < n; i ++) 
            for(int x = 0; x <= 1; x ++)
                for(int y = 0; y <= 1; y ++)
                    for(int t = 0; t <= 1; t ++)
                        for(int m = 0; m <= 1; m ++)
                            if(f[i][x][y][t][m]) trans(i, x, y, t, m);
        for(int x = 0; x <= 1; x ++)
                for(int y = 0; y <= 1; y ++)
                    for(int t = 0; t <= 1; t ++)
                        for(int m = 0; m <= 1; m ++)
                            if((x + y + t + m) == A[n]) 
                                Up(ans, f[n][x][y][t][m]);
        printf("%d
", ans);
    }
    return 0;
}

7.小R的手机

LCT。

8.异或密码

暴力。

9.最大的异或

从高位向低位贪心。

#include <bits/stdc++.h>
using namespace std;
#define int long long
int bits[100], ans;

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k; 
}

signed main() {
    int T = read(); bits[0] = 1;
    for(int i = 1; i <= 61; i ++) bits[i] = bits[i - 1] << 1;
    while(T --) {
        int l = read(), r = read(); ans = 0;
        for(int i = 61; i >= 0; i --) {
            int x = l & bits[i], y = r & bits[i];
            ans += (bits[i] & y);
            if(x != y) {
                for(int j = i - 1; j >= 0; j --) ans += bits[j];
                break; 
            }
        }
        printf("%lld
", ans);
    }
    return 0;
}

10.最大公约数

首先注意到所有模 j 同余的 i f(i, j) 都相等。由于该式中具有一个向下取整的操作,因此不能直接化式子,考虑把所有模 j 同余的 i 的 i * j / f(i, j) 打表出来寻找规律。然后发现其差分数组以 c 为循环节,区别仅仅在于 +- 1 之间(受到取整的影响)。两部分均可以通过等差数列的求和来实现计数。

#include <bits/stdc++.h>
using namespace std;
#define INF 100000000000LL
#define int long long
#define maxn 2000
int n, m, mod, a[maxn], b[maxn];

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

int Get(int x, int y) {
    int c = 0;
    while(y) {
        c += 1;
        int t = x % y;
        x = y, y = t;
    }
    return c * x * x;
}

int count(int x, int y) {
    int c = 0;
    while(y) {
        c += 1;
        int t = x % y;
        x = y, y = t;
    }
    return c;
}

int add(int x, int y) {
    x += y; if(x >= mod) x -= mod;
    return x;
}

int mul(int x, int y) {
    return x * y % mod;
}

int cal(int a0, int l, int d) {
    int a1 = mul(a0, l);
    a1 = add(a1, mul((l * (l - 1)) / 2 % mod, d));
    return a1;
}

signed main() {
    int T = read();
    while(T --) {
        n = read(), m = read(), mod = read(); int ans = 0;
        for(int i = 1; i <= m; i ++) {
            for(int j = 0; j < i; j ++) {
                int C = count(j, i), num = INF, mk = (n - j) / i; int pans = ans;
                int d = Get(j, i);
                if(C > mk) {
                    for(int k = 0; k <= mk; k ++) 
                        ans = add(ans, (k * i + j) * i / d % mod);
                    continue;
                }
                for(int k = 0; k <= C; k ++) {
                    a[k] = (k * i + j) * i / d;
                    if(k) b[k - 1] = a[k] - a[k - 1], num = min(num, b[k - 1]);
                }
                int tans = cal(a[0] % mod, mk + 1, num);
                for(int k = 0; k < C; k ++)
                    if(b[k] != num) {
                        int tt = b[k] - num, f = (mk - k) / C;
                        int q = cal(mk - k, f + 1, -C) % mod;
                        if(q < 0) q += mod; 
                        tans = add(tans, mul(tt, q));
                    }
                ans = add(ans, tans);
            }
        }
        printf("%lld
", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/twilight-sx/p/13916127.html