其他分享
首页 > 其他分享> > Codeforces Round #767 (Div. 1)

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