Codeforces Round 1042 (Div. 3) (A - G)

A. Lever

只需要考虑每个 \(a_i~>~b_i\) 的数,计算差值累加即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    vector<int> a(n+1),b(n+1);
    int ans=0;

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    for(int i=1;i<=n;i++){
        cin>>b[i];
        if(a[i]>b[i]) ans+=a[i]-b[i];
    }

    cout<<ans+1<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

B. Alternating Series

对于奇数:-1 3 -1 3 -1
对于偶数:-1 3 -1 3 -1 3 -1 2 (注意最后一个可以是 \(2\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
	int n;
    cin>>n;

    if(n==2){
        cout<<"-1 2"<<endl;
        return;
    }

    vector<int> a(n+1);
    for(int i=1;i<=n;i+=2){
        a[i]=-1;
    }
    for(int i=2;i<=n;i+=2){
        a[i]=3;
    }
    if((n%2)==0) a[n]=2;

    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }
    cout<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

C. Make it Equal

原题目等价于对于 \(S,T\) 数组中的每个数 \(val\), 可以变成 \(val\%k\)\(k~-~val\%k\)

所以可以将 \(S,T\) 中的每个数变成 \(pair(min(vak\%k,~k~-~val\%k),max(val\%k,~k~-~val\%k))\) 的形式,然会分别排序

判断排序后的 \(pair\) 是否一一对应即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
	int n,k;
    cin>>n>>k;
    vector<pii> s(n+1),t(n+1);
    for(int i=1;i<=n;i++){
        int val;
        cin>>val;
        val%=k;
        int tmp=k-val;
        if(val>tmp) swap(val,tmp);
        s[i]={val,tmp};
    }

    for(int i=1;i<=n;i++){
        int val;
        cin>>val;
        val%=k;
        int tmp=k-val;
        if(val>tmp) swap(val,tmp);
        t[i]={val,tmp};
    }

    sort(s.begin()+1,s.end());
    sort(t.begin()+1,t.end());

    for(int i=1;i<=n;i++){
        if(s[i].first==t[i].first && s[i].second==t[i].second) continue;
        // cout<<s[i].first<<" "<<s[i].second<<" "<<t[i].first<<" "<<t[i].second<<endl;
        cout<<"NO\n";
        return;
    }
    cout<<"YES\n";

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

D. Arboris Contractio

显然变成一个菊花图是最优情况 (特判 \(n=2\)

所以我们要选一个节点作为菊花图的中心节点 \(u\),然后每次操作选择 \(u\) 和一个叶节点 \(v\)

而如果 \(v\)\(u\) 的子节点则无需操作

所以找一个子节点是叶节点的个数最多节点作为 \(u\), 然后每次操作选择不是 \(u\) 子节点的叶节点即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
	int n;
    cin>>n;

    vector<vector<int>> g(n+1);

    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    if(n==2 || n==3){
        cout<<0<<endl;
        return;
    }

    int ye=0;
    for(int i=1;i<=n;i++){
        if(g[i].size()==1) ye++;
    }

    int mx=0;
    for(int i=1;i<=n;i++){
        int cnt=0;
        for(auto v:g[i]){
            if(g[v].size()==1) cnt++;
        }
        mx=max(mx,cnt);
    }
    cout<<ye-mx<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

E. Adjacent XOR

对于 \(a[i]\), 只有两种可能的变化

  1. 和没有变化过的 \(a[i+1]\) 进行异或,这一步可以直接在原数组上从前往后计算一边,如果能变换成 \(b[i]\) 就直接变过去

  2. 和变化过的 \(a[i+1]\) 进行异或,这一步从后往前做,如果 \(a[i+1]\) 已经变成 \(b[i+1]\) 则可以变化

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
	int n;
    cin>>n;

    vector<int> a(n+1),b(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    for(int j=1;j<=n;j++){
        cin>>b[j];
    }

    if(a[n]!=b[n]){
        cout<<"NO\n";
        return;
    }

    for(int i=1;i<n;i++){
        if(a[i]==b[i]) continue;
        if((a[i]^a[i+1])==b[i]) a[i]=b[i];
    }

    for(int i=n-1;i>=1;i--){
        // cout<<a[i]<<" "<<(a[i]^a[i+1])<<" "<<b[i]<<endl;
        if(a[i]==b[i]) continue;
        else if((a[i]^a[i+1])==b[i]) a[i]=b[i];
        else{
            cout<<"NO\n";
            return;
        }
    }
    cout<<"YES\n";
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

F. Unjust Binary Life

如果让 \(f[x] [y] = 0\),则完全等价于让 \(a[1-x]~到~b[1-y]\) 全部相等

所以 \(ans[x] [y]\) 等于让 \(a[1-x]~到~b[1-y]\) 全部变成 \(1\) 或全部变成 \(0\) 的最小代价

暴力做法是 \(O(n^2)\) 的,考虑如何优化

分别设 \(pa1[x],pa0[x],pb1[y],pb0[x]\), 其中 \(pa1[x]\) 表示 \(a\) 的前 \(x\) 个字符中有几个 \(1\)

对于固定的一个 \(x\),考虑对应的每一个 \(y\)

答案即为 \(min(pa1[x]+pb1[y],~pa0[x]+y-pb1[y])\)

\(pa1[x]+pb1[y]~>~pa0[x]+y-pb1[y]\)

\(pa1[x]-pa0[x]~>~y-2*pb1[y]\)

此时这一对 \((x,y)\) 对答案的贡献为 \(pa0[x]+y-pb1[y]\), 否则为 \(pa1[x]+pb1[y]\)

固定 \(x\) 后,可以预处理出 \(y-2*pb1[y]\), 排序后二分即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
	int n;
    cin>>n;
    string s,t;
    cin>>s>>t;
    s=" "+s;
    t=" "+t;

    vector<int> a(n+1),b(n+1),pa0(n+1),pa1(n+1),pb0(n+1),pb1(n+1);
    for(int i=1;i<=n;i++){
        if(s[i]=='1') a[i]=1;
        if(t[i]=='1') b[i]=1;

        pa0[i]=pa0[i-1]+(a[i]==0);
        pa1[i]=pa1[i-1]+a[i];
        pb1[i]=pb1[i-1]+b[i];
        pb0[i]=pb0[i-1]+(b[i]==0);
    }

    int ans=0;

    //当pa0[x]-pa1[x]>2*pb1[y]-y时,用pa1[x]+pb1[y]
    //否则用pa0[x]+pb0[y]

    vector<pii> d(n+1);
    for(int y=1;y<=n;y++){
        d[y]={2*pb1[y]-y,y};
    }

    sort(d.begin()+1,d.end());
    vector<int> td(n+1),ppb1(n+1),py(n+1);

    for(int i=1;i<=n;i++){
        td[i]=d[i].first;
        ppb1[i]=ppb1[i-1]+pb1[d[i].second];
        py[i]=py[i-1]+d[i].second;
    }

    int sumpb1=ppb1[n];
    int sumy=py[n];

    for(int x=1;x<=n;x++){
        int pos=upper_bound(td.begin()+1,td.end(),pa0[x]-pa1[x])-td.begin()-1;

        ans+=pa1[x]*pos+ppb1[pos];
        
        if(pos<n){
            ans+=pa0[x]*(n-pos)+(sumy-py[pos])-(sumpb1-ppb1[pos]);
        }
    }
    cout<<ans<<endl;

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

G. Wafu!

\(f[i]\) 表示移除 \(1-i\) 所有数需要操作多少次,\(f[i]=f[i-1]*2+1\)

\(g[i]\) 表示完全移除 \(1-i\) 后对答案的贡献

\(f[val-1]+1\) 即为完全移除掉 \(val\) 需要的次数,\(g[val-1]*val\) 即为对答案的贡献

发现当 \(i>30\) 时,操作次数已经大于 \(k\)

每次找到集合中最小的数 \(val\),如果 \(f[val-1]+1<=k\),则可以直接把 \(val\) 完全移除

否则,直接枚举 \(i=~[1~到~min(30, val-1)]\),添加到集合中,每次添加的个数不超过 \(30\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 1e9+7;

using mint = ModInt<mod>;


vector<int> f(50);//对于(1-i)会进行多少次操作
vector<mint> g(50);//删完(1-i)要乘上的数值
int mx=1;//数值最大是多少

void init(){
    f[0]=0;
    g[0]=1;

    while(1){
        f[mx]=f[mx-1]*2+1;
        g[mx]=g[mx-1]*g[mx-1]*mx;
        if(f[mx]>=1e9) break;
        mx++;       
    }
}

void solve(){
	int n,k;
    cin>>n>>k;

    set<int> s;
    for(int i=1;i<=n;i++){
        int val;
        cin>>val;
        s.insert(val);
    }

    mint ans=1;

    while(s.size() && k){
        int val=*s.begin();
        s.erase(s.begin());

        if(val<=mx && f[val-1]+1<=k){
            k-=f[val-1]+1;
            ans*=g[val-1]*val;
        }
        else{
            ans*=val;
            k--;

            for(int i=1;i<=min(mx,val-1);i++){
                s.insert(i);
            }
        }
    }
    cout<<ans<<endl;

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    init();

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

自动取模类代码:

点击查看代码
/*支持define int long long 的自动取模类*/
template<const int T>
struct ModInt {
    const static int mod = T;
    int x;
    ModInt(signed x = 0) : x(x % mod) {}
    ModInt(long long x) : x(x % mod) {} 
    int val() { return x; }
    ModInt operator + (const ModInt &a) const { int x0 = x + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
    ModInt operator - (const ModInt &a) const { int x0 = x - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
    ModInt operator * (const ModInt &a) const { return ModInt(1LL * x * a.x % mod); }
    ModInt operator / (const ModInt &a) const { return *this * a.inv(); }
    bool operator == (const ModInt &a) const { return x == a.x; };
    bool operator != (const ModInt &a) const { return x != a.x; };
    void operator += (const ModInt &a) { x += a.x; if (x >= mod) x -= mod; }
    void operator -= (const ModInt &a) { x -= a.x; if (x < 0) x += mod; }
    void operator *= (const ModInt &a) { x = 1LL * x * a.x % mod; }
    void operator /= (const ModInt &a) { *this = *this / a; }
    friend ModInt operator + (int y, const ModInt &a){ int x0 = y + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
    friend ModInt operator - (int y, const ModInt &a){ int x0 = y - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
    friend ModInt operator * (int y, const ModInt &a){ return ModInt(1LL * y * a.x % mod);}
    friend ModInt operator / (int y, const ModInt &a){ return ModInt(y) / a;}
    friend ostream &operator<<(ostream &os, const ModInt &a) { return os << a.x;}
    friend istream &operator>>(istream &is, ModInt &t){return is >> t.x;}

    ModInt pow(int64_t n) const {
        ModInt res(1), mul(x);
        while(n){
            if (n & 1) res *= mul;
            mul *= mul;
            n >>= 1;
        }
        return res;
    }
    
    ModInt inv() const {
        int a = x, b = mod, u = 1, v = 0;
        while (b) {
            int t = a / b;
            a -= t * b; swap(a, b);
            u -= t * v; swap(u, v);
        }
        if (u < 0) u += mod;
        return u;
    }
    
};
using mint = ModInt<mod>;
posted @ 2025-08-11 22:49  LYET  阅读(117)  评论(0)    收藏  举报