2016年中国大学生程序设计竞赛(合肥)-重现赛

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chenzhenyu123456/article/details/53095975

A
充要条件:
如果 u 可以到达 v 点,那么一定有一条 u 直达 v 的有向边。
预处理闭包,然后 c h e c k 一下就好。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long LL;
const int MAXN = 2016 + 100;
const int MOD = 1e9 + 7;
char str[MAXN][MAXN];
bool Map[MAXN][MAXN];
vector<int> P[MAXN], Q[MAXN];
bool vis[MAXN];
void BFSP(int s) {
    queue<int> Q; Q.push(s); vis[s] = true;
    while(!Q.empty()) {
        int u = Q.front(); Q.pop();
        for(int i = 0; i < P[u].size(); i++) {
            int v = P[u][i];
            if(!vis[v]) {
                vis[v] = true;
                Map[s][v] = true;
                Q.push(v);
            }
        }
    }
}
void BFSQ(int s) {
    queue<int> q; q.push(s); vis[s] = true;
    while(!q.empty()) {
        int u = q.front(); q.pop();
        for(int i = 0; i < Q[u].size(); i++) {
            int v = Q[u][i];
            if(!vis[v]) {
                vis[v] = true;
                Map[s][v] = true;
                q.push(v);
            }
        }
    }
}
int main()
{
    int t; scanf("%d", &t);
    while(t--) {
        int n; scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            P[i].clear(); Q[i].clear();
            for(int j = 1; j <= n; j++) {
                Map[i][j] = false;
            }
        }
        for(int i = 1; i <= n; i++) {
            scanf("%s", str[i] + 1);
            for(int j = 1; j <= n; j++) {
                if(str[i][j] == 'P') {
                    P[i].push_back(j);
                }
                else if(str[i][j] == 'Q') {
                    Q[i].push_back(j);
                }
            }
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) vis[j] = false;
            BFSP(i);
        }
        bool flag = true;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(Map[i][j]) {
                    if(str[i][j] != 'P') {
                        flag = false; break;
                    }
                }
                Map[i][j] = false;
            }
            if(!flag) {
                break;
            }
        }
        if(!flag) {
            printf("N\n");
            continue;
        }

        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) vis[j] = false;
            BFSQ(i);
        }

        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(Map[i][j]) {
                    if(str[i][j] != 'Q') {
                        flag = false; break;
                    }
                }
                Map[i][j] = false;
            }
            if(!flag) {
                break;
            }
        }

        printf(flag ? "T\n" : "N\n");
    }
    return 0;
}

C
像这样的题目肯定是套路。多推几次,也就找到套路了。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 4e4 + 10;
const int MOD = 1e9 + 7;
map<pii, bool> fp;
int num[MAXN];
int main()
{
    int t; scanf("%d", &t);
    while(t--) {
        int n, m; scanf("%d%d", &n, &m);
        fp.clear();
        for(int i = 1; i <= n; i++) num[i] = 0;
        for(int i = 1; i <= n - 1; i++) {
            int u, v, w; scanf("%d%d%d", &u, &v, &w);
            if(w == 1) {
                num[u]++; num[v]++;
                if(u > v) {
                    swap(u, v);
                }
                fp[pii(u, v)] = true;
            }
        }
        while(m--) {
            int op, x, y, z;
            scanf("%d", &op);
            if(op == 0) {
                scanf("%d", &x);
                printf(num[x] & 1 ? "Girls win!\n" : "Boys win!\n");
            }
            else {
                scanf("%d%d%d", &x, &y, &z);
                if(x > y) {
                    swap(x, y);
                }
                bool flag = fp[pii(x, y)];
                if(z == 1) {
                    if(!flag) {
                        num[x]++; num[y]++;
                        fp[pii(x, y)] = true;
                    }
                }
                else {
                    if(flag) {
                        num[x]--; num[y]--;
                        fp[pii(x, y)] = false;
                    }
                }
            }
        }
    }
    return 0;
}

E
d p [ i ] [ j ] [ c n t ] 表示处理到第 i 列,第 i 列的状态是 j ,且第 i + 1 列的地雷个数是 c n t 。枚举第 i 1 列的状态,暴力转移即可。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e4 + 10;
const int MOD = 1e8 + 7;
void add(int &x, int y) { x += y; if(x >= MOD) x -= MOD; }
char str[MAXN];
int dp[MAXN][4][3];
int Snum[4] = {0, 1, 1, 2};
int num[MAXN];
int main()
{
    int t; scanf("%d", &t);
    while(t--) {
        scanf("%s", str + 1);
        int len = strlen(str + 1);
        for(int i = 1; i <= len; i++) {
            num[i] = str[i] - '0';
        }
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < 4; i++) {
            for(int j = 0; j <= min(num[1], 2); j++) {
                if(Snum[i] + j == num[1]) {
                    dp[1][i][j] = 1;
                }
            }
        }
        for(int i = 2; i <= len; i++) {
            for(int j = 0; j < 4; j++) {
                if(Snum[j] > num[i]) continue;
                for(int k = 0; k < 4; k++) {
                    int have = num[i] - Snum[j] - Snum[k];
                    if(have >= 0 && have <= 2) {
                        add(dp[i][j][have], dp[i - 1][k][Snum[j]]);
                    }
                }
            }
        }
        int ans = 0;
        for(int i = 0; i < 4; i++) {
            add(ans, dp[len][i][0]);
        }
        printf("%d\n", ans);
    }
    return 0;
}

H

预处理去重,每次二分 c h e c k

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 100 + 10;
struct Node {
    int val, pos;
};
Node num[MAXN][MAXN], rec[MAXN];
int cnt[MAXN];
bool cmp(Node a, Node b) {
    return a.val != b.val ? a.val < b.val : a.pos > b.pos;
}
int a[MAXN], sum[MAXN];
int main()
{
    int t; scanf("%d", &t);
    while(t--) {
        int n; scanf("%d", &n); sum[0] = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            sum[i] = sum[i - 1] ^ a[i];
        }
        for(int i = 1; i <= n; i++) {
            cnt[i] = 0;
            for(int j = i; j <= n; j++) {
                rec[cnt[i]].pos = j;
                rec[cnt[i]].val = sum[j] ^ sum[i - 1];
                cnt[i]++;
            }
            sort(rec, rec + cnt[i], cmp);

            int top = cnt[i]; cnt[i] = 1;
            num[i][0] = rec[0];

            for(int j = 1; j < top; j++) {
                if(rec[j].val != rec[j - 1].val) {
                    num[i][cnt[i]] = rec[j];
                    cnt[i]++;
                }
            }
        }
        int m; scanf("%d", &m);
        while(m--) {
            int x; scanf("%d", &x);
            int ans = 100000, len = 0;
            for(int i = 1; i <= n; i++) {
                if(num[i][cnt[i] - 1].val < x) {
                    int V = abs(num[i][cnt[i] - 1].val - x);
                    int L = num[i][cnt[i] - 1].pos - i + 1;
                    if(V < ans || (V == ans && L > len)) {
                        ans = V; len = L;
                    }
                }
                else {
                    int l = 0, r = cnt[i] - 1;
                    int P;
                    while(r >= l) {
                        int mid = l + r >> 1;
                        if(num[i][mid].val >= x) {
                            P = mid;
                            r = mid - 1;
                        }
                        else {
                            l = mid + 1;
                        }
                    }
                    int V, L;
                    if(P > 0) {
                        V = abs(num[i][P - 1].val - x);
                        L = num[i][P - 1].pos - i + 1;
                        if(V < ans || (V == ans && L > len)) {
                            ans = V; len = L;
                        }
                    }

                    V = abs(num[i][P].val - x);
                    L = num[i][P].pos - i + 1;
                    if(V < ans || (V == ans && L > len)) {
                        ans = V; len = L;
                    }
                }
            }
            printf("%d\n", len);
        }
        printf("\n");
    }
    return 0;
}

I
贪心,维护一个可能出现的最小值 M i n ,最大值 M a x
每次 c h e c k 区间 [ M i n , M a x ] 和区间 [ L R ] 是否相交。

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
LL f[62];
int main()
{
    f[0] = 1;
    for(int i = 1; i <= 61; i++) {
        f[i] = f[i - 1] * 2;
    }
    int T; scanf("%d", &T);
    while(T--) {
        LL l, r; scanf("%lld%lld", &l, &r);
        if(l == 0 && l == r) {
            printf("0\n");
            continue;
        }
        if(l == 0) l++;
        LL ans = r;
        LL Min = 0, Max = 0;
        int pos = -1;
        for(int i = 61; i >= 0; i--) {
            if(r & f[i]) {
                pos = i;
            }
            else {
                if(pos == -1) continue;
                Max = r - f[pos] + Min;
                for(int j = pos - 1; j >= 0; j--) {
                    if(r & f[j]) {

                    }
                    else {
                        Max += f[j];
                    }
                }
                if(Min + f[i] >= r + 1 || Max <= l - 1) {
                    continue;
                }
                ans += f[i];
                Min += f[i];
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/chenzhenyu123456/article/details/53095975
今日推荐