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;
}