一道题20
$n \leq 100000$的字符串,多次问一个区间有多少位置不同的回文串。
先插空做一次manacher,得到每个字符往左右延伸的长度$f$数组。如ACAA变*A*C*A*A*,那么所有*的$f_k$实际对应的回文串数是$\frac{f_k}{2}$(一定整除),否则是$\frac{f_k+1}{2}$(一定整除)。算答案的时候把后者的+1提出来,假设询问原串的区间$l,r$,那就是询问新串的$L=2l-1,R=2r+1$,只要输出$\frac{1}{2}(r-l+1+\sum_{k=L}^{R}min{f_k,k-L,R-k})$即可。
$\sum$那坨东西从$\frac{L+R}{2}$处劈开得到两边,左边是$min{f_k,k-L}$,可以分类把$min$去掉,即$min{f_k,k-L}=f_k,k-f_k \geq L$,$min{f_k,k-L}=k-L,k-f_k<L$,变成了一个二维数点问题,为了方便直接主席树搞定;右边同理。
这个式子很好想到,稍加分析就可以求得,因此见到陌生的式子不要虚,按套路一步步求就好了。
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 //#include<time.h> 5 //#include<math.h> 6 //#include<set> 7 //#include<queue> 8 //#include<bitset> 9 //#include<vector> 10 #include<algorithm> 11 #include<stdlib.h> 12 using namespace std; 13 14 #define LL long long 15 LL qread() 16 { 17 char c; LL s=0; int f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1); 18 do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f; 19 } 20 21 //Pay attention to '-' , LL and double of qread!!!! 22 23 int n,m; 24 #define maxn 260011 25 char s[maxn]; int f[maxn]; 26 int r1[maxn],r2[maxn]; 27 struct SMT 28 { 29 struct Node{int ls,rs; LL f,k,c;}a[maxn*20]; 30 int size,n; 31 void clear(int N) {n=N; size=0;} 32 LL sf,sk,sc; int v; 33 void in(int &x,int y,int L,int R,int p,int f,int k) 34 { 35 x=++size; a[x].f=a[y].f+f; a[x].k=a[y].k+k; a[x].c=a[y].c+1; 36 if (L==R) return; 37 int mid=(L+R)>>1; 38 if (p<=mid) in(a[x].ls,a[y].ls,L,mid,p,f,k),a[x].rs=a[y].rs; 39 else in(a[x].rs,a[y].rs,mid+1,R,p,f,k),a[x].ls=a[y].ls; 40 } 41 void in(int &x,int y,int p,int f,int k) {in(x,y,1,n,p,f,k);} 42 void Query(int x,int L,int R,int ql,int qr) 43 { 44 if (ql<=L && R<=qr) {sf+=a[x].f*v; sk+=a[x].k*v; sc+=a[x].c*v; return;} 45 int mid=(L+R)>>1; 46 if (ql<=mid) Query(a[x].ls,L,mid,ql,qr); 47 if (qr>mid) Query(a[x].rs,mid+1,R,ql,qr); 48 } 49 void query(int x,int y,int l,int r) {sf=sk=sc=0; v=1; Query(y,1,n,l,r); v=-1; Query(x,1,n,l,r);} 50 } 51 t1,t2; 52 53 struct Lisa {int id,v; bool operator < (const Lisa &b) const {return v<b.v;} }lisa1[maxn],lisa2[maxn]; 54 int id1[maxn],id2[maxn]; 55 56 int main() 57 { 58 n=qread(); m=qread(); scanf("%s",s+1); 59 for (int i=n;i;i--) s[i<<1]=s[i]; n=(n<<1)^1; 60 for (int i=1;i<=n;i+=2) s[i]='$'; 61 62 for (int i=1,id=0;i<=n;i++) 63 { 64 if (f[id]+id>=i) f[i]=min(f[id]+id-i,f[id+id-i]); 65 while (i+f[i]+1<=n && i-f[i]-1>0 && s[i+f[i]+1]==s[i-f[i]-1]) f[i]++; 66 if (i+f[i]>f[id]+id) id=i; 67 } 68 69 for (int i=1;i<=n;i++) lisa1[i]=(Lisa){i,i-f[i]},lisa2[i]=(Lisa){i,i+f[i]}; 70 sort(lisa1+1,lisa1+1+n); sort(lisa2+1,lisa2+1+n); 71 for (int i=1;i<=n;i++) id1[lisa1[i].id]=i,id2[lisa2[i].id]=i; 72 t1.clear(n); t2.clear(n); 73 for (int i=1;i<=n;i++) 74 t1.in(r1[i],r1[i-1],id1[i],f[i],i),t2.in(r2[i],r2[i-1],id2[i],f[i],i); 75 76 int l,r; 77 while (m--) 78 { 79 l=qread(); r=qread(); 80 LL ans=r-l+1; 81 l=2*l-1; r=2*r+1; 82 int mid=(l+r)>>1; 83 int p=upper_bound(lisa1+1,lisa1+1+n,(Lisa){0,l})-lisa1-1; 84 t1.query(r1[l-1],r1[mid],1,p); 85 ans+=t1.sk-t1.sc*l; 86 t1.query(r1[l-1],r1[mid],p+1,n); 87 ans+=t1.sf; 88 p=upper_bound(lisa2+1,lisa2+1+n,(Lisa){0,r})-lisa2-1; 89 t2.query(r2[mid],r2[r],1,p); 90 ans+=t2.sf; 91 t2.query(r2[mid],r2[r],p+1,n); 92 ans+=t2.sc*r-t2.sk; 93 printf("%lld\n",ans/2); 94 } 95 return 0; 96 }