CF19C Deletion of Repeats

奇怪的黑题增加了!

考虑一个 \(O(n^2)\) 的做法,从小到大枚举长度然后从左向右移动区间判断是否相等。

code:

#include<bits/stdc++.h>
using namespace std;
#define For(i,x,y)for(i=x;i<=(y);i++)
int a[100005];
int main()
{
	int n,i,len,tot,j,l=0;
	scanf("%d",&n);
	For(i,1,n)scanf("%d",&a[i]);
	a[0]=-1;
	For(len,1,n>>1)
	{
		tot=0;
		For(i,1,len-1)tot+=a[i]==a[i+len];
		For(i,0,n-(len<<1))
		{
			tot+=(a[i+len]==a[i+(len<<1)])-(a[i]==a[i+len]);
			if(i+1>=l&&tot==len)l=i+len+1;
		}
	}
	printf("%d\n",n-l+1);
	For(i,l,n)printf("%d ",a[i]);
	return 0;
}

但我们发现这个做法极其愚蠢,压根没有用到每个字母最多出现十次的性质。考虑一个两个相等的区间,它们不仅相邻,第一个字母也一模一样(废话)。于是可以枚举这个字母,对数最多只有 \(45\)

时间复杂度 \(O(n)\)

code:

#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define Mod 19260817
#define Base 100003
#define For(i,x,y)for(i=x;i<=(y);i++)
bool vis[N];
vector<int>vec[N];
pair<int,int>del[1000000];
int hach[N],a[N],base[N],b[N];
inline int get(int l,int r)
{
	return(hach[r]-1LL*hach[l-1]*base[r-l+1]%Mod+Mod)%Mod;
}
int main()
{
	int n,i,m,j,l=1,k,u,v,cnt=0,tmp;
	scanf("%d",&n);
	base[0]=1;
	For(i,1,n)
	{
		scanf("%d",&a[i]);
		b[i]=a[i];
		base[i]=1LL*base[i-1]*Base%Mod;
	}
	sort(b+1,b+n+1);
	m=unique(b+1,b+n+1)-b-1;
	For(i,1,n)
	{
		tmp=lower_bound(b+1,b+m+1,a[i])-b;
		hach[i]=(1LL*hach[i-1]*Base+tmp)%Mod;
		vec[tmp].push_back(i);
	}
	For(i,1,n)
	{
		tmp=lower_bound(b+1,b+m+1,a[i])-b;
		if(!vis[tmp])vis[tmp]=1;
		else continue;
		For(j,0,int(vec[tmp].size())-2)
		For(k,j+1,int(vec[tmp].size())-1)
		{
			u=vec[tmp][j];
			v=vec[tmp][k];
			if(get(u,v-1)==get(v,v-u+v-1))del[++cnt]=make_pair(v-u,v);
			/*printf("%d %d %d\n",u,v,cnt);*/
		}
	}
	sort(del+1,del+cnt+1);
	For(i,1,cnt)
	if(del[i].second-del[i].first>=l)l=del[i].second;
	printf("%d\n",n-l+1);
	For(i,l,n)printf("%d ",a[i]);
	return 0;
}
posted @ 2021-02-06 15:30  Biadocy  阅读(66)  评论(0编辑  收藏  举报