Codeforces Round #767 (Div. 1)
作者:互联网
A
https://codeforces.com/contest/1628/problem/A
可知前缀mex是单调递增的,字典序最大,则每次选择的mex都是最大的。
贪心地考虑,每次消去一个前缀,要求这个前缀的mex=全局的mex,且是最短的一个,这样可以使得剩余部分的mex也会尽可能大。
代码:
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; int a[N],b[N],c[N],aa[N]; int main() { //freopen("test.in","r",stdin); int t; scanf("%d",&t); while (t) { t--; int n,mex=0; scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); b[a[i]]++; while (b[mex]) mex++; } int p=1,i=1; aa[p]=mex; while (i<=n) { int la=i,me=0; while (i<=n) { c[a[i]]++; while (c[me]) me++; i++; if (me==mex) break; } for (int j=la;j<i;j++) { c[a[j]]--; b[a[j]]--; if (b[a[j]]==0) mex=min(mex,a[j]); } p++; aa[p]=mex; } printf("%d\n",p-1); for (int i=1;i<p-1;i++) printf("%d ",aa[i]); printf("%d\n",aa[p-1]); for (int i=0;i<=n;i++) b[i]=0; } }
B
https://codeforces.com/contest/1628/problem/B
手玩的时候发现,一些很长的组合回文,也会包含一些子序列,同样可以组成回文。
考虑可以组成回文的最简短子序列,也就是要求这个子序列不再包含任何可以回文的子序列。
首先是长度为1的,显然直接回文。
然后是长度为2的,形如AA
长度为3的,可以是AAA,也可以是ABA。当然,有人肯定会说A+BA,或者AB+A,这种情况其实包含了长度为1的情况,不满足最简短的定义。
长度为4的,只有AB+BA,其他的均不是最简短的。
长度为5的,只有ABC+BA,或者AB+CBA。
长度为6的,只有ABC+CBA
更长的长度没有最简短的子序列。
理性证明一下,假设有一个长度为n的最简短子序列,只考虑这个最简短子序列的首和尾的两个小字符串,显然:
1.它们各自不能是即成的回文串,比如A,AA,AAA,ABA
2.它们长度不能相同,否则这两个小串就可以组成更简短的回文子序列。
3.情况只剩下长度分别为2和3的情况,则只能是ABC+BA或AB+CBA,也不合法
综上,没有合法情况。
所以,所有的回文子序列都可以缩小成长度不超过6的最简短回文子序列。
依次判断即可。
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int g[10],a[N],b[N][4],q[4][N],fv[N],gv[N],f1[N]; int main() { //freopen("test.in","r",stdin); int t; scanf("%d",&t); while (t) { g[1]=g[2]=g[3]=0; t--; int n; scanf("%d",&n); for (int i=1;i<=n;i++) { char s[5]; scanf("%s",s+1); int p=strlen(s+1); a[i]=p; for (int j=1;j<=p;j++) b[i][j]=s[j]-'a'; g[p]++; q[p][g[p]]=i; } if (g[1]) { printf("YES\n"); continue; } int fl=0; for (int i=0;i<=30*30;i++) fv[i]=0,f1[i]=0; for (int i=1;i<=n;i++) { if (a[i]==2) { if (b[i][1]==b[i][2]) fl=1; fv[b[i][1]*26+b[i][2]]=1; //gv[b[i][1]+b[i][2]*26]=1; if (fv[b[i][1]+b[i][2]*26]||f1[b[i][1]+b[i][2]*26]) fl=1; }else { if (b[i][1]==b[i][3]) fl=1; f1[b[i][1]*26+b[i][2]]=1; gv[b[i][3]+b[i][2]*26+b[i][1]*26*26]=1; if (fv[b[i][2]+b[i][3]*26]||gv[b[i][1]+b[i][2]*26+b[i][3]*26*26]) fl=1; } } for (int i=1;i<=n;i++) if (a[i]==3) gv[b[i][3]+b[i][2]*26+b[i][1]*26*26]=0; if (fl) { printf("YES\n"); continue; } printf("NO\n"); } }
C
https://codeforces.com/contest/1628/problem/C
赛场上没想出来。
4个这样的东西就可以了。
D1
https://codeforces.com/contest/1628/problem/D1
设f[i][j]表示i次加和j次减所能到达的最大值。
假设我们已经知道了f[i-1][j]和f[i][j-1],考虑如何确定f[i][j]
假设这一轮,给出的数字是p,则f[i][j]=max(f[i-1][j]+p,f[i][j-1]+p),由于双方都绝顶聪明,
标签:int,767,Codeforces,序列,长度,Div,简短,mex,回文 来源: https://www.cnblogs.com/lmlysklt/p/15841583.html