您的位置:首页 > 其它

[bzoj4516] [Sdoi2016]生成魔咒

2016-06-19 15:51 615 查看
  强行上hash。。复杂度两个log。。

  把字符串倒过来。就是每次加一个后缀。。就变成问一个后缀会产生多少个不同子串的板子题了。

  听说是SAM板子题..这辈子学不会SAM系列>_<

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
#define ull unsigned long long
using namespace std;
const int maxn=100233,base=1e9+9;
int lc[maxn],rc[maxn],val[maxn],rnd[maxn],tot;
ull pre[maxn],jc[maxn];
int s[maxn],sa[maxn],rk[maxn];
int i,j,k,n,m,AFT,PRE,V,rt;
ll ans;

int ra;char rx;
inline int read(){
rx=getchar(),ra=0;
while(rx<'0'||rx>'9')rx=getchar();
while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
}
inline int getlcp(int a,int b){
if(s[a]!=s[b])return 0;
if(a>b)swap(a,b);
int r=n-b+1;
a--,b--;
if(pre
-pre[b]*jc[r]==pre[a+r]-pre[a]*jc[r])return r;
int l=1,mid;
while(l<r)
if(pre[b+(mid=l+r+1>>1)]-pre[b]*jc[mid]==pre[a+mid]-pre[a]*jc[mid])
l=mid;else r=mid-1;
return l;
}
inline bool cmp(int a,int b){
int lcp=getlcp(a,b);
return s[a+lcp]<s[b+lcp];
}
inline void getsa(){
int i;
for(i=jc[0]=1;i<=n;i++)pre[i]=pre[i-1]*base+s[i],jc[i]=jc[i-1]*base,sa[i]=i;
sort(sa+1,sa+1+n,cmp);
for(i=1;i<=n;i++)rk[sa[i]]=i;//,printf("   %d",sa[i]);puts("");
//  for(i=1;i<=n;i++)printf("   %d",rk[i]);puts("");
}

inline void lturn(int &x){int R=rc[x];rc[x]=lc[R],lc[R]=x,x=R;}
inline void rturn(int &x){int L=lc[x];lc[x]=rc[L],rc[L]=x,x=L;}
inline void insert(int &x){
if(!x){x=++tot,val[x]=V,rnd[x]=rand()+tot;return;}
if(V<val[x]){
insert(lc[x]);
if(rnd[lc[x]]<rnd[x])rturn(x);
}else{
insert(rc[x]);
if(rnd[rc[x]]<rnd[x])lturn(x);
}
}
void getpre(int x){
if(!x)return;
if(val[x]<V)PRE=val[x],getpre(rc[x]);
else getpre(lc[x]);
}
void getaft(int x){
if(!x)return;
if(val[x]>V)AFT=val[x],getaft(lc[x]);
else getaft(rc[x]);
}
int main(){
n=read();
for(i=n;i;i--)s[i]=read();
//      n=1e5;  for(i=n;i;i--)s[i]=1;
getsa();//return 233;
ans=1,V=rk
,insert(rt);printf("%lld\n",ans);
for(i=n-1;i;i--){
PRE=AFT=0,V=rk[i],getpre(rt),getaft(rt);
//      printf("i:%d  rk:%d   pre:%d  aft:%d\n",i,rk[i],PRE,AFT);
if(!PRE||!AFT)ans+=n-i+1-getlcp(i,sa[PRE|AFT]);
else ans+=n-i+1-max(getlcp(i,sa[PRE]),getlcp(i,sa[AFT]));
printf("%lld\n",ans);
V=rk[i],insert(rt);
}//printf("  %lld\n",ans);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: