3572. 【GDKOI2014】基因模式 (Standard IO)
Time Limits: 1000 ms Memory Limits: 262144 KB
对于询问串S,定义near[i]为以第i位为起点同时为T的子串的最长串的长度,则Si-i+near[i]-1串的任一子串都为T的子串
求解near的过程用SA和rmq实现
然后用一个二进制数表示对各个字母的奇偶性要求。f[i]表示以满足奇偶性为i的字符串数
对于第i位,为S子串的起点和终点为i和i+near[i]-1,这两个值都单调不下降。
对于末尾的转移,设x为后一位字母用二进制表示的奇偶性,f[i]=f'[i^x],且f[x]=f[x]+1(表示增加这一位的单个字符串)
对于首的转移,在对应位减一即可
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> using namespace std; int i,t,n,mj,ext,mn,x,len,j; int sa[300011],rank[300011],h[300011],co[300011],nr[300011]; int a[300011],b[300011],near[300011],f[3][30],bel[300011],ans[1011]; int lef[300011],rig[300011]; char s[300011],s1[1011]; bool p[1011][5]; struct tree{ int x,z,q; }tr[1200011]; void Read() { char c; while(c=getchar(),c<'A'||c>'Z'); s[++n]=c; bel[n]=i; while(c=getchar(),c>='A'&&c<='Z'){ s[++n]=c; bel[n]=i; } } void sort(int *a) { int i; for(i=0;i<=mn;i++)co[i]=0; for(i=1;i<=n;i++)co[a[i]+1]++; for(i=1;i<=mn;i++)co[i]+=co[i-1]; for(i=1;i<=n;i++)nr[i]=0; for(i=1;i<=n;i++){ co[a[sa[i]]]++; nr[co[a[sa[i]]]]=sa[i]; } for(i=1;i<=n;i++)sa[i]=nr[i]; } void getrank() { int i; x=0; for(i=1;i<=n;i++){ if(i==1||a[sa[i]]!=a[sa[i-1]]||b[sa[i]]!=b[sa[i-1]])x++; rank[sa[i]]=x; } mn=x; } void Suffix() { int i,j,k,l,last; for(i=1;i<=n;i++){ if(s[i]!='#')a[i]=s[i]-64; b[i]=0; sa[i]=i; } sort(a); getrank(); l=1; while(x!=n){ for(i=1;i<=n;i++){ a[i]=rank[i]; if(i+l<=n)b[i]=rank[i+l]; else b[i]=0; } sort(b); sort(a); getrank(); l*=2; } last=0; for(i=1;i<=n;i++){ if(last)last--; if(rank[i]==1)continue; j=i; k=sa[rank[i]-1]; while(j+last<=n&&k+last<=n&&s[j+last]==s[k+last]&&s[j+last]!='#')last++; h[rank[i]]=last; } } void build(int l,int r,int t) { int mid; if(l==r){ tr[t].x=l; tr[t].z=r; tr[t].q=h[l]; return; } tr[t].x=l; tr[t].z=r; mid=(l+r)/2; build(l,mid,t+t); build(mid+1,r,t+t+1); tr[t].q=min(tr[t+t].q,tr[t+t+1].q); } int ask(int l,int r,int t) { int mid; if(l==tr[t].x&&r==tr[t].z)return tr[t].q; mid=(tr[t].x+tr[t].z)/2; if(r<=mid)return ask(l,r,t+t); if(l>mid)return ask(l,r,t+t+1); if(l<=mid&&r>mid)return min(ask(l,mid,t+t),ask(mid+1,r,t+t+1)); } void Work(int x) { int i,j,k,l,rn,xzq,ap,ple,z,q,xz,r,e; bool pp; xzq=0; for(i=mj;i<=n;i++){ if(bel[i]!=x)break; rn=i-mj+1; l=lef[rank[i]]; r=rig[rank[i]]; if(l!=0){ if(l<rank[i])ap=ask(l+1,rank[i],1); else ap=ask(rank[i]+1,l,1); } if(r!=0){ if(r<rank[i])ple=ask(r+1,rank[i],1); else ple=ask(rank[i]+1,r,1); } if(ap>ple)near[rn]=ap; else near[rn]=ple; } for(i=0;i<=15;i++){ f[0][i]=0; f[1][i]=0; } z=0; l=1; for(i=mj;i<=n;i++){ if(bel[i]!=x)break; rn=i-mj+1; if(rn!=1){ f[1-l][z]--; if(s[i-1]=='A')z^=1; if(s[i-1]=='G')z^=2; if(s[i-1]=='C')z^=4; if(s[i-1]=='T')z^=8; } for(j=rn-1+near[rn-1];j<rn+near[rn];j++)if(j!=0){ if(s[j+mj-1]=='A')xz=1; if(s[j+mj-1]=='G')xz=2; if(s[j+mj-1]=='C')xz=4; if(s[j+mj-1]=='T')xz=8; z^=xz; for(k=0;k<=15;k++)f[l][k]=f[1-l][k^xz]; f[l][xz]++; for(k=0;k<=15;k++){ pp=true; if(p[x][1]==false){ q=k&1; e=ans[x]&1; if(q!=e)pp=false; } if(p[x][2]==false){ q=k&2; e=ans[x]&2; if(q!=e)pp=false; } if(p[x][3]==false){ q=k&4; e=ans[x]&4; if(q!=e)pp=false; } if(p[x][4]==false){ q=k&8; e=ans[x]&8; if(q!=e)pp=false; } if(pp)xzq+=f[l][k]; } l=1-l; } } mj=i+1; printf("%d ",xzq); } int main() { memset(p,true,sizeof(p)); scanf("%d",&t); i=0; Read(); mj=n+2; ext=27; for(i=1;i<=t;i++){ s[++n]='#'; a[n]=ext++; Read(); scanf("%s",&s1); len=strlen(s1); for(j=0;j<len;j++){ if(s1[j]=='A')ans[i]^=1; if(s1[j]=='G')ans[i]^=2; if(s1[j]=='C')ans[i]^=4; if(s1[j]=='T')ans[i]^=8; if(s1[j]=='A'||s1[j]=='a')p[i][1]=false; if(s1[j]=='G'||s1[j]=='g')p[i][2]=false; if(s1[j]=='C'||s1[j]=='c')p[i][3]=false; if(s1[j]=='T'||s1[j]=='t')p[i][4]=false; } } mn=ext; Suffix(); lef[0]=0; for(i=1;i<=n;i++){ if(bel[sa[i]]==0)lef[i]=i; else lef[i]=lef[i-1]; } rig[n+1]=0; for(i=n;i>=1;i--){ if(bel[sa[i]]==0)rig[i]=i; else rig[i]=rig[i+1]; } build(1,n,1); for(i=1;i<=t;i++)Work(i); }