Codeforces Round #629 (Div. 3) 总结

废话

前期题过得还是有点慢

题解

A

直接数出余数的补就好

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

int a,b,t;

signed main() {
    cin>>t;
    while(t--) {
        cin>>a>>b;
        cout<<(b-a%b)%b<<endl;
    }
}

B

给这些串分个类,很容易发现没类的个数依次是 (1,2,3,dots)

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

#define int long long
const int N = 100005;

int t,n,k;

signed main() {
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin>>n>>k;
        int pos=1;
        while(k>pos) k-=pos, ++pos;
        ++pos;
        int q=k;
        for(int i=n;i>=1;--i) cout<<((i==pos||i==q)?'b':'a');
        cout<<endl;
    }
}

C

从第一个 (1) 之后,将所有的数字倒到另一边

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

#define int long long
const int N = 100005;

char c[N],a[N],b[N];

int t,n;

signed main() {
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin>>n>>c+1;
        int fg=0;
        for(int i=1;i<=n;i++) {
            if(fg==0) {
                if(c[i]=='1') {
                    a[i]='1';
                    b[i]='0';
                    fg=1;
                }
                else if(c[i]=='2') {
                    a[i]='1';
                    b[i]='1';
                }
                else {
                    a[i]='0';
                    b[i]='0';
                }
            }
            else {
                a[i]='0';
                b[i]=c[i];
            }
        }
        for(int i=1;i<=n;i++) cout<<a[i];
        cout<<endl;
        for(int i=1;i<=n;i++) cout<<b[i];
        cout<<endl;
    }
}

D

如果能二分图染色就输出颜色数,否则就输出 (3)

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

#define int long long
const int N = 400005;

int q,n,a[N],c[N],fail;
vector <int> g[N];

void dfs(int p) {
    for(int q:g[p]) {
        if(c[q]) {
            if(c[q]==c[p]) fail=1;
        }
        else {
            c[q]=3-c[p];
            dfs(q);
        }
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>q;
    while(q--) {
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        int fg=0;
        for(int i=1;i<n;i++) if(a[i]!=a[i+1]) fg=1;
        if(a[1]!=a[n]) fg=1;
        if(fg==0) {
            cout<<1<<endl;
            for(int i=1;i<=n;i++) cout<<1<<" ";
            cout<<endl;
            continue;
        }
        for(int i=1;i<n;i++) if(a[i]!=a[i+1]) {
            g[i].push_back(i+1);
            g[i+1].push_back(i);
        }
        if(a[1]!=a[n]) {
            g[1].push_back(n);
            g[n].push_back(1);
        }
        fail=0;
        for(int i=1;i<=n;i++) if(c[i]==0) {
            c[i]=1;
            dfs(i);
        }
        if(fail) {
            cout<<3<<endl;
            for(int i=1;i<n;i++) cout<<(i%2)+1<<" ";
            cout<<3<<endl;
        }
        else {
            cout<<2<<endl;
            for(int i=1;i<=n;i++) cout<<c[i]<<" ";
            cout<<endl;
        }
        for(int i=1;i<=n;i++) {
            a[i]=c[i]=0;
            g[i].clear();
        }
    }
}

E

给定一棵有根树,每次询问给定一个点集,问是否存在根到某点的链,使得点集中所有点到链的距离不大于 (1)

将每次询问的结点按深度排序好,相邻的两个结点 (p,q) 一定满足 (d[p]-d[lca] le 1 or d[q]-d[lca] le 1),其中 (lca=lca(p,q))

必要性显然,充分性考虑让毛毛虫的茎一直往差值大的那边走即可

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

#define int long long
const int N = 200005;

vector <int> g[N];
int n,m,t1,t2,t3,dep[N],fa[N][20];

void dfs(int p) {
    for(int q:g[p]) {
        if(dep[q]) continue;
        dep[q]=dep[p]+1;
        fa[q][0]=p;
        dfs(q);
    }
}

int lca(int p,int q) {
    if(dep[p]<dep[q]) swap(p,q);
    for(int i=18;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) p=fa[p][i];
    for(int i=18;i>=0;--i) if(fa[p][i]-fa[q][i]) p=fa[p][i],q=fa[q][i];
    if(p-q) return fa[p][0];
    else return p;
}

bool cmp(const int &p,const int &q) {
    return dep[p]<dep[q];
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<n;i++) {
        cin>>t1>>t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    dep[1]=1;
    dfs(1);
    for(int i=1;i<=18;i++) {
        for(int j=1;j<=n;j++) {
            fa[j][i]=fa[fa[j][i-1]][i-1];
        }
    }
    for(int i=1;i<=m;i++) {
        int k;
        cin>>k;
        vector <int> vec;
        for(int j=0;j<k;j++) {
            int t;
            cin>>t;
            vec.push_back(t);
        }
        sort(vec.begin(),vec.end(),cmp);
        int fg=1;
        for(int j=1;j<k;j++) {
            int p=vec[j],q=vec[j-1];
            int l=lca(p,q);
            if(dep[p]-dep[l]>1 && dep[q]-dep[l]>1) fg=0;
        }
        cout<<(fg?"YES":"NO")<<endl;
    }
}

F

枚举选择一个中间点,计算把边上压到中间这条线上的答案

压的时候要考虑两边压和单边压的情况

(以下代码中的二分显得很累赘,纯粹为了偷懒而出现)

using namespace std;

#define int long long
const int N = 200005;

int n,k,a[N],pre[N],suf[N],ans=1e18;
map<int,int> mp;

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) {
        pre[i]=pre[i-1]+a[i];
    }
    for(int i=n;i>=1;--i) {
        suf[i]=suf[i+1]+a[i];
    }
    for(int i=1;i<=n;i++) mp[a[i]]++;
    for(auto i:mp) if(i.second>=k) {
        cout<<0<<endl;
        return 0;
    }
    for(int i=1;i<=n;i++) {
        int x=a[i];
        int e=upper_bound(a+1,a+n+1,x)-lower_bound(a+1,a+n+1,x);
        int g=n-(upper_bound(a+1,a+n+1,x)-a)+1;
        int l=lower_bound(a+1,a+n+1,x)-a-1;
        int sg=suf[n-g+1];
        int sl=pre[l];
        int tmp=sg-g*x+l*x-sl-(n-k);
        ans=min(ans,tmp);
        if(n-l>=k) {
            int tx=sg-g*x-(n-l-k);
            ans=min(ans,tx);
        }
        if(n-g>=k) {
            int tx=l*x-sl-(n-g-k);
            ans=min(ans,tx);
        }
        //cout<<l<<" "<<e<<" "<<g<<endl;
    }
    cout<<max(0ll,ans);
}

原文地址:https://www.cnblogs.com/mollnn/p/12579022.html