[bzoj4516] [Sdoi2016]生成魔咒
强行上hash。。复杂度两个log。。
把字符串倒过来。就是每次加一个后缀。。就变成问一个后缀会产生多少个不同子串的板子题了。
听说是SAM板子题..这辈子学不会SAM系列>_<
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define ll long long 6 #define ull unsigned long long 7 using namespace std; 8 const int maxn=100233,base=1e9+9; 9 int lc[maxn],rc[maxn],val[maxn],rnd[maxn],tot; 10 ull pre[maxn],jc[maxn]; 11 int s[maxn],sa[maxn],rk[maxn]; 12 int i,j,k,n,m,AFT,PRE,V,rt; 13 ll ans; 14 15 16 int ra;char rx; 17 inline int read(){ 18 rx=getchar(),ra=0; 19 while(rx<'0'||rx>'9')rx=getchar(); 20 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 21 } 22 inline int getlcp(int a,int b){ 23 if(s[a]!=s[b])return 0; 24 if(a>b)swap(a,b); 25 int r=n-b+1; 26 a--,b--; 27 if(pre[n]-pre[b]*jc[r]==pre[a+r]-pre[a]*jc[r])return r; 28 int l=1,mid; 29 while(l<r) 30 if(pre[b+(mid=l+r+1>>1)]-pre[b]*jc[mid]==pre[a+mid]-pre[a]*jc[mid]) 31 l=mid;else r=mid-1; 32 return l; 33 } 34 inline bool cmp(int a,int b){ 35 int lcp=getlcp(a,b); 36 return s[a+lcp]<s[b+lcp]; 37 } 38 inline void getsa(){ 39 int i; 40 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; 41 sort(sa+1,sa+1+n,cmp); 42 for(i=1;i<=n;i++)rk[sa[i]]=i;//,printf(" %d",sa[i]);puts(""); 43 // for(i=1;i<=n;i++)printf(" %d",rk[i]);puts(""); 44 } 45 46 inline void lturn(int &x){int R=rc[x];rc[x]=lc[R],lc[R]=x,x=R;} 47 inline void rturn(int &x){int L=lc[x];lc[x]=rc[L],rc[L]=x,x=L;} 48 inline void insert(int &x){ 49 if(!x){x=++tot,val[x]=V,rnd[x]=rand()+tot;return;} 50 if(V<val[x]){ 51 insert(lc[x]); 52 if(rnd[lc[x]]<rnd[x])rturn(x); 53 }else{ 54 insert(rc[x]); 55 if(rnd[rc[x]]<rnd[x])lturn(x); 56 } 57 } 58 void getpre(int x){ 59 if(!x)return; 60 if(val[x]<V)PRE=val[x],getpre(rc[x]); 61 else getpre(lc[x]); 62 } 63 void getaft(int x){ 64 if(!x)return; 65 if(val[x]>V)AFT=val[x],getaft(lc[x]); 66 else getaft(rc[x]); 67 } 68 int main(){ 69 n=read(); 70 for(i=n;i;i--)s[i]=read(); 71 // n=1e5; for(i=n;i;i--)s[i]=1; 72 getsa();//return 233; 73 ans=1,V=rk[n],insert(rt);printf("%lld\n",ans); 74 for(i=n-1;i;i--){ 75 PRE=AFT=0,V=rk[i],getpre(rt),getaft(rt); 76 // printf("i:%d rk:%d pre:%d aft:%d\n",i,rk[i],PRE,AFT); 77 if(!PRE||!AFT)ans+=n-i+1-getlcp(i,sa[PRE|AFT]); 78 else ans+=n-i+1-max(getlcp(i,sa[PRE]),getlcp(i,sa[AFT])); 79 printf("%lld\n",ans); 80 V=rk[i],insert(rt); 81 }//printf(" %lld\n",ans); 82 return 0; 83 } 84