1. 程式人生 > >[BZOJ4340][BJOI2015]隱身術(字尾陣列)

[BZOJ4340][BJOI2015]隱身術(字尾陣列)

考慮到K很小,於是可以暴搜每次用的是哪種操作,跳過AB相等的字元可以用SA求LCP加速。

主要流程就是,列舉B的每個字尾,對每個字尾統計合法字首個數。DFS搜尋每次決策,用SA跳過相同字元,當A或B匹配到結尾時統計答案。

每次某個串匹配到結尾時,B中的某個區間的字首都會合法,注意到這些合法的字首長度與A長度相差一定不超過K,於是用一個2*K+1的差分陣列記錄答案即可。複雜度$O(n\log n+n3^K)$

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define
rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int N=200010; 8 int K,m,na,nb,n,d,ans,lg[N],h[N],c[N],x[N],y[N],sa[N],rk[N],st[N][20]; 9 char s[N],A[N],B[N]; 10 11 bool Cmp(int a,int b,int l){ return y[a]==y[b] && y[a+l]==y[b+l]; } 12 13 void getSA(int
m){ 14 memset(y,0,sizeof(y)); 15 rep(i,0,m) c[i]=0; 16 rep(i,1,n) c[x[i]=s[i]]++; 17 rep(i,1,m) c[i]+=c[i-1]; 18 for (int i=n; i; i--) sa[c[x[i]]--]=i; 19 for (int k=1,p=0; p<n; k<<=1,m=p){ 20 p=0; rep(i,n-k+1,n) y[++p]=i; 21 rep(i,1,n) if (sa[i]>k) y[++p]=sa[i]-k;
22 rep(i,0,m) c[i]=0; 23 rep(i,1,n) c[x[y[i]]]++; 24 rep(i,1,m) c[i]+=c[i-1]; 25 for (int i=n; i; i--) sa[c[x[y[i]]]--]=y[i]; 26 rep(i,0,n) y[i]=x[i]; p=1; x[sa[1]]=1; 27 rep(i,2,n) x[sa[i]]=Cmp(sa[i],sa[i-1],k)?p:++p; 28 } 29 } 30 31 void getH(){ 32 rep(i,1,n) rk[sa[i]]=i; int k=0; 33 rep(i,1,n){ 34 for (int j=sa[rk[i]-1]; j+k<=n && i+k<=n && s[i+k]==s[j+k]; k++); 35 h[rk[i]]=k; if (k) k--; 36 } 37 } 38 39 void init(){ 40 lg[1]=0; rep(i,2,n) lg[i]=lg[i>>1]+1; 41 rep(i,1,n) st[i][0]=h[i]; 42 rep(i,1,19) rep(j,1,n-(1<<i)+1) st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]); 43 } 44 45 int lcp(int l,int r){ 46 int x=rk[l],y=rk[r+na+1]; 47 if (x>y) swap(x,y); 48 x++; int t=lg[y-x+1]; 49 return min(st[x][t],st[y-(1<<t)+1][t]); 50 } 51 52 void col(int l,int r){ l=max(l,d); r=min(r,nb); c[K-(na-(l-d+1))+1]++; c[K-(na-(r-d+1))+2]--; } 53 54 void dfs(int x,int y,int z){ 55 int t=lcp(x,y); x+=t; y+=t; 56 if (x>na || y>nb){ 57 int c=K-z-(na-x+1); 58 if (c>=0) col(y-1-c,y-1+c); 59 return; 60 } 61 if (z==K) return; 62 dfs(x+1,y,z+1); dfs(x,y+1,z+1); dfs(x+1,y+1,z+1); 63 } 64 65 int main(){ 66 freopen("bzoj4340.in","r",stdin); 67 freopen("bzoj4340.out","w",stdout); 68 scanf("%d%s%s",&K,A+1,B+1); m=2*K+1; 69 na=strlen(A+1); nb=strlen(B+1); 70 rep(i,1,na) s[++n]=A[i]; s[++n]='#'; 71 rep(i,1,nb) s[++n]=B[i]; 72 getSA(300); getH(); init(); 73 for (d=1; d<=nb; d++){ 74 rep(j,1,m) c[j]=0; 75 dfs(1,d,0); 76 rep(j,1,m){ 77 c[j]+=c[j-1]; 78 if (c[j]) ans++; 79 } 80 } 81 printf("%d\n",ans); 82 return 0; 83 }