Educational Codeforces Round 186(CF2182)

A. New Year String

首先扫一遍整个字符串,计算\(2025\)的个数和\(2026\)的个数,如果\(2025\)个数为\(0\)\(2026\)个数不为\(0\),那么不用变,否则一定有至少一个\(2025\),我们把这个\(2025\)\(5\)变为\(6\),那么\(2026\)的个数就不为\(0\)了,所以变\(1\)次即可。

点击查看代码
//仲夏初芒,七月未央。
#include<bits/stdc++.h>

using namespace std;

int n;
string s;

void qy(){
    
    cin >> n >> s;

    int gs2025 = 0,gs2026 = 0;
    
    for(int i = 0;i+3 < n;++ i){
        if(s[i] == '2'&&s[i+1] == '0'&&s[i+2] == '2'){
            if(s[i+3] == '5') gs2025++;
            else if(s[i+3] == '6') gs2026++;
        }
    }

    if(gs2026||!gs2025) cout << 0 << '\n';
    else cout << 1 << '\n';
    
}

signed main(){

    int _;cin >> _;
    while(_--) qy();
    
    return 0;
    
}

B. New Year Cake

分两种情况,白巧给奇数层,黑巧给偶数层;或者,黑巧给奇数层,白巧给偶数层。两种分配方式算最大层数的方法是完全一样的,复制一下就行了。那么怎么算呢?
我们先处理出来每一层需要多少千克巧克力,然后做两个前缀和,一个前缀和只加奇数层,另一个只加偶数层。分别对于奇数层和偶数层算一下最后一个小于等于给这些层的巧克力总数的是哪一层,那么对于这种层,就可以覆盖到这一层,那么对于两种层可覆盖到的层数取\(min\)即可。

点击查看代码
//仲夏初芒,七月未央。
#include<bits/stdc++.h>

using namespace std;

int x,y;

vector<int> v;
vector<int> q1,q2;

void qy(){

    cin >> x >> y;

    int ans;

    int a = upper_bound(q1.begin(),q1.end(),x)-q1.begin()-1;
    int b = upper_bound(q2.begin(),q2.end(),y)-q2.begin()-1;
    a++;b++;
    ans = min(a,b);

    swap(x,y);

    a = upper_bound(q1.begin(),q1.end(),x)-q1.begin()-1;
    b = upper_bound(q2.begin(),q2.end(),y)-q2.begin()-1;
    a++;b++;
    ans = max(ans,min(a,b));

    cout << ans << '\n';
    
}

signed main(){

    int _ = 1;
    while(_ <= 1e6)
        v.push_back(_),_ *= 2;
    _ = 0;
    for(int i = 0;i < v.size();++ i){
        if(i%2 == 0) _ += v[i];
        q1.push_back(_);
    }
    _ = 0;
    q2.push_back(0);
    for(int i = 1;i < v.size();++ i){
        if(i%2 == 1) _ += v[i];
        q2.push_back(_);
    }
    cin >> _;
    while(_--) qy();
    
    return 0;
    
}

C. Production of Snowmen

考虑用所有的减去不满足条件的。
我们考虑一个\((i,j,k)\)不行的条件就是\(\exists o\),使得\(a_{i+o} \geq b_{j+o}\)\(b_{j+o} \geq c_{k+o}\)。(为什么不写\(a_{i+o} \geq c_{k+o}\)?因为至少满足前面两个条件中的一个才会有\(a_{i+o} \geq c_{k+o}\),想一下为什么。)
也就是说如果\(\exists o\),使得\(a_{i+o} \geq b_{j+o}\)\(b_{j+o} \geq c_{k+o}\),那么这个\((i,j,k)\)就是不满足条件的。
考虑先算仅满足\(\exists o\),使得\(a_{i+o} \geq b_{j+o}\)\((i,j,k)\)有多少个,可以枚举\(i\)\(j\),如果\(a_i \geq b_j\),那么就把不满足条件的个数加上\(n \times n\),其中一个\(n\)是这对\((i,j)\)的所有的\(n\)个循环,也就是\((i+0,j+0)\)\((i+1,j+1)\),……,因为对于任意的\(x\),第\(x\)个循环\((i+x,j+x,k+x)\)都会满足\(\exists o\),使得\(a_{i+x+o} \geq b_{j+x+o}\)(让\(o\)等于\(-x\)\(n\)取余即可),另一个\(n\)是指的从\(n\)\(k\)里任选一个,因为这个条件与\(k\)无关,所以\(k\)可以任选。
我们记\(j = i+x\),那么可以发现,当两对\((i,j)\)\(x\)相等时,一定是可以从一对循环到另一对的,那么我们就会算重。所以我们考虑枚举这个\(x\),看看\(j = i+x\)的所有\((i,j)\)中有没有满足\(a_i \geq b_j\)的,如果没有,就算了,但如果有,不管有几个,也就只算一遍,算一遍就能把所有循环都算上了,这样就不会算重了。
我们再考虑计算满足\(\exists o\),使得\(b_{j+o} \geq c_{k+o}\)\((i,j,k)\)有多少个,那么也是一样的算法,只是这次的\(i\)就不能任选了,因为如果选到了一个\(\exists o\),使得\(a_{i+o} \geq b_{j+o}\)\(i\),那么就会和前面算重(因为前面的\(k\)是任选的),所以我们要选那些不满足\(\exists o\),使得\(a_{i+o} \geq b_{j+o}\)\(i\),这里\(j\)是要循环到\(1~n\)中的每一个数的,那么这里算的\(i\)的个数的总和就是有多少个\((i,j)\)满足\(\exists o\),使得\(a_{i+o} \geq b_{j+o}\)。那么这次我们每次加的就不是\(n \times n\)了,而是还要减去\((i,j)\)满足\(\exists o\),使得\(a_{i+o} \geq b_{j+o}\)的个数。这个怎么算?类比上面,如果有一个\(a_i \geq a_j\),那么它的\(n\)个循环就都是满足条件的\((i,j)\),个数就要加\(n\),只是同样要注意两对\((i,j)\)可以从一对循环到另一对从而会算重的情况。

点击查看代码
//仲夏初芒,七月未央。
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n;
int a[5005],b[5005],c[5005];

void qy(){

    cin >> n;
    for(int i = 0;i < n;++ i)
        cin >> a[i];
    for(int i = 0;i < n;++ i)
        cin >> b[i];
    for(int i = 0;i < n;++ i)
        cin >> c[i];

    int ans = n*n*n,le = 0;

    for(int o = 0;o < n;++ o){
        bool fl = 0;
        for(int i = 0;i < n;++ i)
            if(a[i] >= b[(i+o)%n]){
                fl = 1;
                break;
            }
        if(fl) ans -= n*n,le += n;
    }

    for(int o = 0;o < n;++ o){
        bool fl = 0;
        for(int i = 0;i < n;++ i)
            if(b[i] >= c[(i+o)%n]){
                fl = 1;
                break;
            }
        if(fl) ans -= n*n-le;
    }

    cout << ans << '\n';
    
}

signed main(){

    int _;cin >> _;
    while(_--) qy();
    
    return 0;
    
}

D. Christmas Tree Decoration

先换一种说法描述题意:将\(a_1\)\(a_n\)重排,然后一个指针\(]p\)循环\(1\)\(n\),每次将\(a_p\)\(1\),如果减不了了就把\(a_0\)\(1\),如果\(a_p\)\(a_0\)都减不了了那么这种重排方式就不合法,问有多少种重排方式是合法的。
首先声明一下,下面所有的\(sum\)都代表了\(a_0\)加到\(a_n\)的和。
那么首先我们知道,指针\(p\)一共会循环完整的\(\lfloor \frac{sum}{n} \rfloor\)轮,记\(\lfloor gs = \frac{sum}{n} \rfloor\),那么我们对于所有的\(1 \leq i \leq n\),让\(a_i\)减去\(gs\)\(1\)(其实就是减去\(gs\)),如果不够减的就把减不了的那一部分减到\(a_0\)上,那么最终如果\(a_0 < 0\)了,那么肯定没有一种重排方式是合法的,答案就是\(0\)了。
那么剩下的\(a_1\)\(a_n\),不能有任何一个是除了\(0\)\(1\)外的数字,因为如果它不是\(0\)\(1\),那么指针循环一次肯定不可能变成\(0\),而由于我们前面的叙述,指针不可能完整的循环一次了,那就更不可能变成\(0\)了,所以如果有一个是除了\(0\)\(1\)外的数字,那么没有一种重排方式合法,答案为\(0\)
那么剩下的情况答案就一定不为\(0\)了,这时我们考虑计算答案。
我们记剩下的\(0\)的个数为\(cnt_0\),剩下的\(1\)的个数为\(cnt_1\)。那么指针还会移动\(cnt_1+a_0\)次,记为\(mt\),因为指针移动到的位置是前\(mt\)个位置,所以对前\(mt\)个数就有要求:前\(mt\)个数一定要包含所有的\(1\),否则就有无法变成\(0\)的位置了(而且这样正好能让剩下的\(mt-cnt_1 = a_0\)\(0\)\(a_0\)减成\(0\))。那么我们就是在\(mt\)个位置中选出来\(cnt_1\)个位置放\(1\)\(C_{mt}^{cnt_1}\)),然后剩下的所有位置放\(0\),但是这里所有\(0\)\(1\)是有区别的,所以还要乘上\(cnt_1\)的阶乘和\(cnt_0\)的阶乘(排列的个数)。

点击查看代码
//仲夏初芒,七月未央。
#include<bits/stdc++.h>

#define int long long
#define mod 998244353

using namespace std;

int n;
int a[55];

int ksm(int a,int b){
    if(b == 0) return 1;
    int z = ksm(a,b/2);
    z *= z;z %= mod;
    if(b%2) z *= a;
    return z%mod;
}

int fac[55];
int infac[55];

int C(int n,int m){
    return fac[n]*infac[m]%mod*infac[n-m]%mod;
}

void qy(){

    cin >> n;
    int sum = 0;
    for(int i = 0;i <= n;++ i)
        cin >> a[i],sum += a[i];
    int gs = sum/n;

    for(int i = 1;i <= n;++ i){
        if(a[i] >= gs) a[i] -= gs;
        else a[0] -= gs-a[i],a[i] = 0;
    }

    if(a[0] < 0){
        cout << 0 << '\n';
        return;
    }

    int cnt0,cnt1;cnt0 = cnt1 = 0;
    for(int i = 1;i <= n;++ i){
        if(a[i] != 0&&a[i] != 1){
            cout << 0 << '\n';
            return;
        }
        if(a[i]) cnt1++;
        else cnt0++;
    }

    int al = cnt1+a[0];

    int ans = C(al,cnt1)%mod;
    ans *= fac[cnt1];ans %= mod;
    ans *= fac[cnt0];ans %= mod;

    cout << ans << '\n';
    
}

signed main(){

    fac[0] = 1;
    for(int i = 1;i <= 52;++ i)
        fac[i] = fac[i-1]*i%mod;
    infac[52] = ksm(fac[52],mod-2);
    for(int i = 51;i >= 0;-- i)
        infac[i] = infac[i+1]*(i+1)%mod;

    int _;cin >> _;
    while(_--) qy();
    
    return 0;
    
}

E. New Year's Gifts

点击查看代码
//仲夏初芒,七月未央。
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n,m,k;
int a[200005];
struct nd{
    int x,y,z,gs;
}c[200005];

bool cmp(nd o,nd t){
    if(o.gs == t.gs) return o.z-o.y < t.z-t.y;
    return o.gs < t.gs;
}

priority_queue<int> q;
priority_queue<int,vector<int>,greater<int> > q2;

void qy(){

    cin >> n >> m >> k;

    for(int i = 1;i <= m;++ i)
        cin >> a[i];
    sort(a+1,a+1+m);
    for(int i = 1;i <= n;++ i){
        cin >> c[i].x >> c[i].y >> c[i].z;
        c[i].gs = lower_bound(a+1,a+1+m,c[i].x)-a;
        k -= c[i].y;
    }

    sort(c+1,c+1+n,cmp);

    q.push(c[1].z-c[1].y);
    int wl = c[1].gs;
    c[n+1].gs = m+1;
    for(int i = 2;i <= n+1;++ i){
        if(c[i].gs != c[i-1].gs){
            int wr = c[i].gs-1;
            while(!q.empty()&&wl <= wr) q.pop(),wl++;
            wl = wr+1;
        }
        if(i != n+1) q.push(c[i].z-c[i].y);
    }

    int ans = n-q.size();

    while(!q.empty()) q2.push(q.top()),q.pop();

    while(!q2.empty()&&q2.top() <= k){
        k -= q2.top();q2.pop();
        ans++;
    }

    cout << ans << '\n';

    while(!q2.empty()) q2.pop();
    
}

signed main(){

    int _;
    cin >> _;
    while(_--) qy();
    
    return 0;
    
}
posted @ 2026-04-01 21:07  u_uICLMFu_uX  阅读(6)  评论(0)    收藏  举报