ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

设第i个字母的权值为1<<i,则一个可重集合可以重排为回文串,当且仅当这个集合的异或和x满足x==x&-x,用莫队维护区间内有多少对异或前缀和,异或后满足x==x&-x,这样端点移动的代价为字符集大小+1=27,因此时间复杂度为$O(27n\sqrt{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\n",as[i]);
    return 0;
}

 

posted on 2017-08-23 08:05  nul  阅读(243)  评论(0编辑  收藏  举报