Educational Codeforces Round 83 总结

A

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

int t,n,m;

signed main() {
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin>>n>>m;
        if(n%m==0) puts("YES");
        else puts("NO");
    }
}

B

给定序列 \(a\),构造一个解,将它重新排序后,称为一个新的序列,使得 \(j-i \neq a_j-a_i\)

排序后再翻转

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

int t,n,a[105];

signed main() {
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+n+1);
        reverse(a+1,a+n+1);
        for(int i=1;i<=n;i++) cout<<a[i]<<" ";
        cout<<endl;
    }
}

C

能否对一个初态都为 \(0\) 数组执行任意次操作,使他变成目标数组。第 \(i\) 次操作可以放弃,或者给某个元素加上 \(k^i\)

\(k=1\) 的特判掉,剩下的相当于一个进制分解判重

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

#define int long long
const int N = 100;
const int lim = 1e16;

int t,n,k,a[N],u[N];

signed main() {
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin>>n>>k;
        for(int i=1;i<=n;i++) cin>>a[i];
        if(k==1) {
            puts("YES");
            continue;
        }
        memset(u,0,sizeof u);
        int fg=0;
        for(int i=1;i<=n;i++) {
            for(int j=0;j<=66;j++) {
                if(a[i]%k==1) {
                    ++u[j];
                }
                else if(a[i]%k>1) {
                    puts("NO");
                    goto AERR;
                }
                a[i]/=k;
            }
        }

        for(int i=0;i<=66;i++) fg=max(fg,u[i]);
        if(fg>1) puts("NO");
        else puts("YES");
        AERR:cout<<"";
    }
}

D

求长度为 \(n\) 的序列 \(a\) 的个数:\(a_i \in [1,m]\),存在且仅存在一对相同元素,存在 \(p\) 使得 \(a[1...p]\) 严格单增,\(a[p...n]\) 严格单调递减

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

#define int long long
const int mod = 998244353;

int qpow(int p,int q) {
    return (q&1?p:1) * (q?qpow(p*p%mod,q/2):1) % mod;
}

int frac(int p) {
    int res = 1;
    for(int i=1;i<=p;i++) res *= i, res %= mod;
    return res;
}

int inv(int p) {
    return qpow(p,mod-2);
}

signed main() {
    int n,m;
    cin>>n>>m;
    int ans=frac(m)*inv(frac(n-1))%mod*inv(frac(m-n+1))%mod;
    ans=ans*(n-2)%mod*qpow(2,n-3)%mod;
    cout<<ans;
}

E

给定一个长度为 \(n \leq 500\) 的数组 \(a\),元素均 \(\leq 1000\),每次你可以找到 \(i\) 使得 \(a[i]=a[i+1]\),将它们替换成一个数 \(a_i+1\),求剩余数组长度的最小值

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

#define int long long
const int N = 505;

int n,a[N],f[N][N],g[N][N];

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=-1;
    for(int i=1;i<=n;i++) f[i][i]=a[i];
    for(int l=1;l<n;l++) {
        for(int i=1;i+l<=n;i++) {
            int j=i+l;
            for(int k=i;k<j;k++) {
                if(f[i][k]>0 && f[k+1][j]>0 && f[i][k]==f[k+1][j]) {
                    f[i][j]=f[i][k]+1;
                }
            }
        }
    }
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) {
        if(f[i][j]==-1) g[i][j]=1e9;
        else g[i][j]=1;
    }
    for(int l=1;l<n;l++) {
        for(int i=1;i+l<=n;i++) {
            int j=i+l;
            for(int k=i;k<j;k++) {
                g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]);
            }
        }
    }
    cout<<g[1][n];
}

F

\(n\) 个数,甲乙两人轮流操作,甲先手,每次操作有三个选项

  • 将一个 \(>0\) 的数 \(-x\)
  • 将一个 \(>0\) 的数 \(-y\)
  • 将一个 \(>0\) 的数 \(-z\)

如果操作后这个数 \(<0\) 则自动变为 \(0\)

对于一个数,如果上次对这个数操作是第二种,那么这次就不能操作第二种,如果上次对这个数操作是第三种,那么这次就不能操作第三种

不能操作的人输,问甲先手,第一步有多少种办法使得自己必胜

Solution

首先可以将各个 \(a_i\) 分开来考虑,最后将结果异或起来就是局面的 SG 值

\(SG(x,c)\) 表示在这个数为 \(x\),上次操作为 \(c\) 时的 SG 值,那么转移很显然是
\[ SG(i,0)=\text{mex} \{ SG(i-x,0),SG(i-y,1),SG(i-z,2) \} \\ SG(i,1)=\text{mex} \{ SG(i-x,0),SG(i-z,2) \} \\ SG(i,2)=\text{mex} \{ SG(i-x,0),SG(i-y,1) \} \]
由于 \(x,y,z\) 很小,所以 \(SG\) 函数一定有一个很小的循环节

#include <bits/stdc++.h>

using namespace std;
#define int long long

int mex(set<int> s) {
    for(int i=0;i<=4;i++) if(s.find(i)==s.end()) return i;
}

int x,y,z;

namespace sg {
    int sg[105][4];
    int I,J;
    int getsg(int t,int c) {
        if(t<J) return sg[t][c];
        return sg[J+(t-J)%(I-J)][c];
    }
    void clear() {
        I=0; J=0;
        memset(sg,0,sizeof sg);
    }
    void calc(int ai) {
        for(int i=1;;i++) {
            set<int> s;
            s.insert(sg[max(0ll,i-x)][0]);
            s.insert(sg[max(0ll,i-y)][1]);
            s.insert(sg[max(0ll,i-z)][2]);
            sg[i][0]=mex(s);
            s.clear();
            s.insert(sg[max(0ll,i-x)][0]);
            s.insert(sg[max(0ll,i-z)][2]);
            sg[i][1]=mex(s);
            s.clear();
            s.insert(sg[max(0ll,i-x)][0]);
            s.insert(sg[max(0ll,i-y)][1]);
            sg[i][2]=mex(s);
            for(int j=4;j<i-4;j++) {
                int fg=1;
                for(int k=0;k<=4;k++) {
                    for(int u=0;u<3;u++) {
                        if(sg[j-k][u]!=sg[i-k][u]) fg=0;
                    }
                }
                if(fg) {
                    I=i;
                    J=j;
                    return;
                }
            }
        }
    }
}

int t,n,a[300005],ssg[300005][3],osg[300005];

signed main() {
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin>>n>>x>>y>>z;
        for(int i=1;i<=n;i++) cin>>a[i];
        sg::clear();
        sg::calc(0);
        int sum=0;
        for(int i=1;i<=n;i++) {
            osg[i]=sg::getsg(a[i],0);
            sum^=osg[i];
            ssg[i][0]=sg::getsg(max(0ll,a[i]-x),0);
            ssg[i][1]=sg::getsg(max(0ll,a[i]-y),1);
            ssg[i][2]=sg::getsg(max(0ll,a[i]-z),2);
        }
        int ans=0;
        for(int i=1;i<=n;i++) {
            if((sum^osg[i]^ssg[i][0])==0) ++ans;
            if((sum^osg[i]^ssg[i][1])==0) ++ans;
            if((sum^osg[i]^ssg[i][2])==0) ++ans;
        }
        cout<<ans<<endl;
    }
}

G

给定一个字符串集合 \(S\),需要计算打 \(S\) 中所有字符串花费的时间总和

打一个字符串的步骤如下:从一个空串开始;如果当前的字符串是 \(t\),你可以末尾拼接任意一个小写字母,花费 \(1s\)

你可以使用自动补全功能,设当前字符串是 \(t\),此时所有 \(s\in S\) 会按照字典序展现出来,自动补全到第 \(i\) 个串需要 \(is\)

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

const int inf=1e9;
const int N=1e+6+5;

struct node {
    char c;
    int nxt;
    bool operator < (const node &b) const {
        return c<b.c;
    }
};
int n,m,q[N],tar[N],ans[N];

vector <node> g[N];

int dfs(int u,int c) {
    int rk=0;
    if(tar[u]) ans[u]=min(ans[u],c), ++rk;
    for(int i=0;i<g[u].size();i++) {
        int v=g[u][i].nxt;
        ans[v]=ans[u]+1;
        rk+=dfs(v,min(ans[v],c)+rk);
    }
    return rk;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) {
        int t;
        char c;
        cin>>t>>c;
        g[t].push_back({c,i});
    }
    for(int i=0;i<n;i++) sort(g[i].begin(),g[i].end());
    cin>>m;
    for(int i=1;i<=m;i++) {
        cin>>q[i];
        tar[q[i]]=1;
    }
    dfs(0,inf);
    for(int i=1;i<=m;i++) cout<<ans[q[i]]<<" ";
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12531167.html