设第i个字母的权值为1<<i,则一个可重集合可以重排为回文串,当且仅当这个集合的异或和x满足x==x&-x,用莫队维护区间内有多少对异或前缀和,异或后满足x==x&-x,这样端点移动的代价为字符集大小+1=27,因此时间复杂度为$O(27nsqrt{m})$
#include<cstdio> #include<cmath> #include<algorithm> char buf[3000000],*ptr=buf-1; int _(){ int x=0,c=*++ptr; while(c<48)c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x; } typedef unsigned int u32; const int P=2939999,N=61007; int n,q,xs[N][27]; int hx[P][2],idp=0; int getid(int x){ int w=x%P; while(hx[w][1]){ if(hx[w][0]==x)return hx[w][1]; if((w+=12347)>=P)w-=P; } hx[w][0]=x; return hx[w][1]=++idp; } u32 as[N],pos[N],B,ans=0,t[N*27]; struct Q{ int l,r,id; }qs[N]; bool operator<(Q a,Q b){ if(pos[a.l]!=pos[b.l])return pos[a.l]<pos[b.l]; if(a.r!=b.r)return (a.r<b.r)^(pos[a.l]&1); return a.id<b.id; } void ins(int*x){ for(int i=0;i<=26;++i)ans+=t[x[i]]; ++t[x[26]]; } void del(int*x){ --t[x[26]]; for(int i=0;i<=26;++i)ans-=t[x[i]]; } int main(){ fread(buf,1,sizeof(buf),stdin)[buf]=0; n=_();q=_(); B=(n+1)/sqrt(q+1)+1; for(int i=0;i<=n;++i)pos[i]=i/B; while(*ptr<'a')++ptr; for(int i=1;i<=n;++i)xs[i][26]=xs[i-1][26]^1<<*ptr++-'a'; for(int i=0;i<=n;++i){ for(int j=0;j<26;++j)xs[i][j]=xs[i][26]^1<<j; } for(int i=0;i<=n;++i){ for(int j=0;j<=26;++j)xs[i][j]=getid(xs[i][j]); } for(int i=0;i<q;++i){ qs[i].l=_()-1; qs[i].r=_(); qs[i].id=i; } std::sort(qs,qs+q); int L=1,R=0; for(int i=0;i<q;++i){ int l=qs[i].l,r=qs[i].r; while(L>l)ins(xs[--L]); while(R<r)ins(xs[++R]); while(L<l)del(xs[L++]); while(R>r)del(xs[R--]); as[qs[i].id]=ans; } for(int i=0;i<q;++i)printf("%u ",as[i]); return 0; }