[比赛题解] Codeforces Round 940 (Div 2) and CodeCraft- 949676b86e1241c7ad1e7f9102221f4f

Codeforces Round 940 (Div 2) 比赛题解

[比赛题解] Codeforces Round 940 (Div. 2) and CodeCraft-23

比赛链接:Codeforces Round 940 (Div. 2) and CodeCraft-23 - Codeforces

C. How Does the Rook Move?

经过若干步合法步骤后,答案可以看作在空白的 n × n n\times n n×n棋盘上放置棋子。

考虑 n × n n\times n n×n棋盘上第一行被什么占据:

(1) 被 ( 1 , 1 ) (1,1) (1,1)的白棋占据,则剩余一个 ( n − 1 ) × ( n − 1 ) (n-1)\times(n-1) (n1)×(n1)棋盘。

(2) 被 ( 1 , i ) (1,i) (1,i) ( i , 1 ) (i,1) (i,1)的白棋占据,剩余一个 ( n − 2 ) × ( n − 2 ) (n-2)\times(n-2) (n2)×(n2)棋盘。

设方案数为 d p [ n ] dp[n] dp[n],得到dp方程 d p [ n ] = d p [ n − 1 ] + 2 ( i − 1 ) d p [ n − 2 ] dp[n]=dp[n-1]+2(i-1)dp[n-2] dp[n]=dp[n1]+2(i1)dp[n2]

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

const int MAXN = 300000+5;
const int N = 300000;
const int mod = 1e9+7;
int T, n, k;
int dp[MAXN];

int main(){
    dp[0] = dp[1] = 1;
    for(int i = 2; i <= N; i++){
        dp[i] = (dp[i-1] + (ll)dp[i-2]*2*(i-1)) % mod;
    }
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &k);
        while(k--){
            int x, y;
            scanf("%d%d", &x, &y);
            if(x == y)  n--;
            else  n -= 2;
        }
        printf("%d\n", dp[n]);
    }
    return 0;
}

D. A BIT of an Inequality

按二进制位考虑,若有 f ( x , y ) ⊕ f ( y , z ) > f ( x , z ) f(x,y)\oplus f(y,z)>f(x,z) f(x,y)f(y,z)>f(x,z),则在 a y a_y ay的最高二进制位上, a x ⊕ a x + 1 ⊕ ⋯ ⊕ a z a_x\oplus a_{x+1}\oplus\dots\oplus a_z axax+1az 在该位为 0 0 0。即在该二进制位上, a [ x , y ) a[x,y) a[x,y)内1的个数加 a ( y , z ] a(y,z] a(y,z]内1的个数为奇数,统计每个二进制位上使得 a [ i , y ) a[i,y) a[i,y)内1的个数为奇数和使得 a ( y , i ] a(y,i] a(y,i]内1的个数为奇数的 i i i的个数,即可计算答案。

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

const int MAXN = 100000+5;
int T, n;
int a[MAXN], cl[40], cr[40], cnt[40];
ll ans;

int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
        }
        for(int i = 0; i <= 30; i++){
            cnt[i] = 0;
            cl[i] = cr[i] = 0;
        }
        for(int i = 2; i <= n; i++){
            for(int k = 0; k <= 30; k++){
                cnt[k] += (a[i] >> k) & 1;
                if(cnt[k] & 1)
                    cr[k]++;
            }
        }
        ans = 0;
        for(int i = 1; i <= n; i++){
            for(int k = 30; k >= 0; k--){
                if((a[i] >> k) & 1){
                    // printf("i = %d k = %d\n", i, k);
                    // printf("cl %lld cr %lld\n", cl[k], cr[k]);
                    ans += (ll)cl[k] * (n-i-cr[k]+1);
                    ans += (ll)(i-1-cl[k]+1) * cr[k];
                    break;
                }
            }
            for(int k = 0; k <= 30; k++){
                if((a[i] >> k) & 1){
                    cl[k] = i - cl[k];
                }
                if((a[i+1] >> k) & 1){
                    cr[k] = n-i-cr[k];
                }
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

E. Carousel of Combinations

C ( i , j ) = i ! j ( i − j ) !  mod  j C(i,j)=\frac{i!}{j(i-j)!} \ \text{mod}\ j C(i,j)=j(ij)!i! mod j

打表找规律+线段树/树状数组维护差分数组后计算答案

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

const int MAXN = 1000000+5;
const int N = 1000000;
const ll mod = 1e9+7;
int T;
ll n;
int len[MAXN<<2];
ll ans[MAXN], sum[MAXN<<2], tag[MAXN<<2];

int isp(int n){
    if(n <= 1)  return 0;
    for(int i = 2; i*i <= n; i++)
        if(n%i == 0)  return 0;
    return 1;
}

void build(int x, int l, int r){
    len[x] = r-l+1;
    if(l == r)  return;
    int mid = (l+r)/ 2;
    build(x<<1, l, mid);
    build(x<<1|1, mid+1, r);
}

void push_up(int x){
    sum[x] = sum[x<<1] + sum[x<<1|1];
}

void push_down(int x, int l, int r){
    if(tag[x]){
        int mid = (l+r)/2, ls = x<<1, rs = x<<1|1;
        tag[ls] = tag[ls] + tag[x];
        sum[ls] = sum[ls] + tag[x]*len[ls];
        tag[rs] = tag[rs] + tag[x];
        sum[rs] = sum[rs] + tag[x]*len[rs];
        tag[x] = 0;
    }
}

void add(int x, int l, int r, int L, int R, ll c){
    if(L <= l && r <= R){
        sum[x] = sum[x] + c*len[x];
        tag[x] = tag[x] + c;
        return; 
    }
    push_down(x, l, r);
    int mid = (l+r)/2;
    if(R <= mid)  add(x<<1, l, mid, L, R, c);
    else  if(L > mid)  add(x<<1|1, mid+1, r, L, R, c);
    else{
        add(x<<1, l, mid, L, mid, c);
        add(x<<1|1, mid+1, r, mid+1, R, c);
    }
    push_up(x);
}

ll query(int x, int l, int r, int L, int R){
    if(L <= l && r <= R)  return sum[x];
    push_down(x, l, r);
    int mid = (l+r) / 2;
    if(R <= mid)  return query(x<<1, l, mid, L, R);
    if(L > mid)  return query(x<<1|1, mid+1, r, L, R);
    return query(x<<1, l, mid, L, mid) + query(x<<1|1, mid+1, r, mid+1, R);
}

int main(){
    build(1, 1, N);
    for(int i = 2; i <= N; i++){
        if(isp(i)){
            int x = i-1;
            for(int l = i, r = min(N, l+i-1); l <= N; l = r+1, r = min(N, l+i-1)){
                // printf("lrx %d %d %lld\n", l, r, x);
                add(1, 1, N, l, r, x);
                x = (x-1+i) % i;
            }
        }
    }
    int x = 2;
    for(int l = 4, r = min(N, l+4-1); l <= N; l = r+1, r = min(N, l+4-1)){
        add(1, 1, N, l, r, x);
        x ^= 2;
    }
    for(int i = 1; i <= N; i++){
        ans[i] = query(1, 1, N, 1, i) % mod;
    }
    scanf("%d", &T);
    while(T--){
        scanf("%lld", &n);
        printf("%lld\n", ans[n]);
    }
    return 0;
}

F2. Frequency Mismatch (Hard Version)

对于树上每个节点 u u u维护一个表示 ( 1 , u ) (1,u) (1,u)路径上经过点集的权值线段树,在线段树的每个节点上保存区间上有关频率的哈希值。比较两条路径上点构成的可重集是否相同,就是比较不同线段树区间的哈希值。设 f ( u ) f(u) f(u) ( 1 , u ) (1,u) (1,u)路径上经过点集的权值线段树,则路径 ( u , v ) (u,v) (u,v)的信息由 f ( u ) + f ( v ) − f ( l c a ) − f ( f a [ l c a ] ) f(u)+f(v)-f(lca)-f(fa[lca]) f(u)+f(v)f(lca)f(fa[lca])得到。用线段树方法可以找到两条路径在 [ 1 , 100000 ] [1,100000] [1,100000]内出现次数不同的最小值 C C C,下次在 [ C + 1 , 100000 ] [C+1,100000] [C+1,100000]内寻找下一个。

#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pii;

const int MAXN = 100000+5;
const int N = 100000;
const int mod1 = 1e9+7;
const int mod2 = 1e9+9;
int n, tot, q;
int a[MAXN], fa[MAXN][17], dep[MAXN];
int rt[MAXN], ls[MAXN<<5], rs[MAXN<<5];
mt19937 rnd(time(0));
pii base, val[MAXN<<5], pw[MAXN];
vector<int> G[MAXN];
int u1, v1, u2, v2, c1, c2;

pii operator + (const pii &a, const pii &b){
	int c1 = a.fi + b.fi, c2 = a.se + b.se;
	if(c1 >= mod1)  c1 -= mod1;
	if(c2 >= mod2)  c2 -= mod2;
	return mp(c1, c2);
}
pii operator - (const pii &a, const pii &b){
	int c1 = a.fi - b.fi, c2 = a.se - b.se;
	if(c1 < 0)  c1 += mod1;
	if(c2 < 0)  c2 += mod2;
	return mp(c1, c2);
}
pii operator * (const pii &a, const pii &b){
	return mp(1ll*a.fi*b.fi%mod1, 1ll*a.se*b.se%mod2);
}

void init_hash(int lim = 0){
	base = {rnd()%mod1, rnd()%mod2};
	pw[0] = mp(1, 1);
	for(int i = 1; i <= lim; i++)  pw[i] = pw[i-1] * base;
}

void push_up(int dir){
    val[dir] = val[ls[dir]] + val[rs[dir]];
}

int update(int pos, int l, int r, int root){
    int dir = ++tot;
    ls[dir] = ls[root];
    rs[dir] = rs[root];
    if(l == r){
        val[dir] = val[root] + pw[l];
        // printf("l = %d %d %d %d\n", l, dir, val[dir].fi, val[dir].se);
        return dir;
    }
    int mid = (l+r) / 2;
    if(pos <= mid)
        ls[dir] = update(pos, l, mid, ls[dir]);
    else
        rs[dir] = update(pos, mid+1, r, rs[dir]);
    push_up(dir);
    return dir;
}

void dfs(int u, int f){
    fa[u][0] = f;
    dep[u] = dep[f] + 1;
    rt[u] = update(a[u], 1, N, rt[f]);
    for(int v : G[u]){
        if(v == f)  continue;
        dfs(v, u);
    }
}

int getlca(int u, int v){
    if(dep[u] < dep[v])  swap(u, v);
    for(int i = 0; i <= 16; i++){
        if(((dep[u] - dep[v]) >> i) & 1){
            u = fa[u][i];
        }
    }
    if(u == v)  return u;
    for(int i = 16; i >= 0; i--){
        if(fa[u][i] != fa[v][i]){
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}

pii calc(int u1, int u2, int u3, int u4){
    pii tmp = val[u1] + val[u2] - val[u3] - val[u4];
    return val[u1] + val[u2] - val[u3] - val[u4];
}

int find(int u1, int u2, int u3, int u4, int v1, int v2, int v3, int v4, int l, int r, int L, int R){
    // printf("%d %d %d %d %d %d %d %d %d %d %d %d\n", u1, u2, u3, u4, v1, v2, v3, v4, l, r, L, R);
    if(l == r){
        pii h1 = calc(u1, u2, u3, u4);
        pii h2 = calc(v1, v2, v3, v4);
        return h1 == h2 ? N+1 : l;
    }
    int mid = (l+r) / 2;
    if(L <= l && r <= R){
        pii h1 = calc(ls[u1], ls[u2], ls[u3], ls[u4]);
        pii h2 = calc(ls[v1], ls[v2], ls[v3], ls[v4]);
        if(h1 == h2)  return find(rs[u1], rs[u2], rs[u3], rs[u4], rs[v1], rs[v2], rs[v3], rs[v4], mid+1, r, mid+1, R);
        else  return find(ls[u1], ls[u2], ls[u3], ls[u4], ls[v1], ls[v2], ls[v3], ls[v4], l, mid, L, mid);
    }
    if(R <= mid)  return find(ls[u1], ls[u2], ls[u3], ls[u4], ls[v1], ls[v2], ls[v3], ls[v4], l, mid, L, R);
    if(L > mid)  return find(rs[u1], rs[u2], rs[u3], rs[u4], rs[v1], rs[v2], rs[v3], rs[v4], mid+1, r, L, R);
    return min(find(ls[u1], ls[u2], ls[u3], ls[u4], ls[v1], ls[v2], ls[v3], ls[v4], l, mid, L, mid), find(rs[u1], rs[u2], rs[u3], rs[u4], rs[v1], rs[v2], rs[v3], rs[v4], mid+1, r, mid+1, R));
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
    }
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    init_hash(N);
    dfs(1, 0);
    // for(int i = 1; i <= n; i++){
    //     printf("%d %d %d %d\n", i, rt[i], ls[rt[i]], rs[rt[i]]);
    // }
    for(int j = 1; j <= 16; j++){
        for(int i = 1; i <= n; i++){
            fa[i][j] = fa[fa[i][j-1]][j-1];
        }
    }
    scanf("%d", &q);
    while(q--){
        int k;
        scanf("%d%d%d%d%d", &u1, &v1, &u2, &v2, &k);
        c1 = getlca(u1, v1);
        c2 = getlca(u2, v2);
        // printf("%d %d lca %d\n", u1, v1, c1);
        // printf("%d %d lca %d\n", u2, v2, c2);
        int C = 1;
        vector<int> ans;
        while(k > 0 && C <= N){
            // printf("l = %d\n", C);
            C = find(rt[u1], rt[v1], rt[c1], rt[fa[c1][0]], rt[u2], rt[v2], rt[c2], rt[fa[c2][0]], 1, N, C, N);
            k--;
            if(C <= N)  ans.push_back(C);
            C++;
        }
        printf("%d ", ans.size());
        for(int p : ans)
            printf("%d ", p);
        putchar('\n');
    }
    return 0;
}
### Codeforces Round 1005 Div. 2 A-F Problem Solutions #### A. Money Change 为了处理货币转换问题,可以将所有的金额都转化为分的形式来简化计算。通过遍历输入数据并累加各个部分的金额,最后求得剩余的钱数并对100取模得到最终结果[^2]。 ```cpp #include <iostream> using namespace std; int main() { int s, xi, yi; cin >> s; int total_cents = 0; for (int i = 0; i < s; ++i) { cin >> xi >> yi; total_cents += xi * 100 + yi; } cout << (s * 100 - total_cents) % 100 << endl; } ``` #### B. Odd and Even Pairs 此题目要求找到至少一对满足条件的索引:要么是一个偶数值的位置,或者是两个奇数值位置。程序会读入测试次数`t`以及每次测试中的数组长度`n`及其元素,并尝试找出符合条件的一对索引输出;如果没有这样的组合则返回-1[^3]。 ```cpp #include <cstdio> int main() { int t, n, num; scanf("%d", &t); while (t--) { int evenIndex = 0, oddIndex1 = 0, oddIndex2 = 0; scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d", &num); if (num % 2 == 0 && !evenIndex) evenIndex = i; else if (num % 2 != 0) { if (!oddIndex1) oddIndex1 = i; else if (!oddIndex2) oddIndex2 = i; } if ((evenIndex || (oddIndex1 && oddIndex2))) break; } if (evenIndex) printf("1\n%d\n", evenIndex); else if (oddIndex1 && oddIndex2) printf("2\n%d %d\n", oddIndex1, oddIndex2); else printf("-1\n"); } return 0; } ``` 由于仅提供了前两道题的具体描述和解决方案,在这里无法继续给出完整的C至F题解答。通常情况下,每一道竞赛编程题都有其独特的挑战性和解决方法,建议查阅官方题解或社区讨论获取更多帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值