由乃的题还是一如既往的可怕……
先放上原题解
标解:
一个区间可以重排成为回文串,即区间中最多有一个字母出现奇数次,其他的都出现偶数次
发现这个和 类似
这样如果一个区间的 和为 或者 ,则这个区间可以重排成为回文串,即回归天空
把每个位置的值变为前缀 和,那么区间 可以回归天空当且仅当 为 或者
即 的异或和
这样用莫队算法,可以做到 的复杂度
然后怎么用莫队?可以参考一下这道题目->异或序列
考虑区间$[l,r]->[l,r+1]$就是要看这个区间里有多少前缀异或$a[r+1]$等于$0$或$1<<x$
那么只要用桶存起来就好了
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 inline int read(){ 8 #define num ch-'0' 9 char ch;bool flag=0;int res; 10 while(!isdigit(ch=getchar())) 11 (ch=='-')&&(flag=true); 12 for(res=num;isdigit(ch=getchar());res=res*10+num); 13 (flag)&&(res=-res); 14 #undef num 15 return res; 16 } 17 char sr[1<<21],z[20];int C=-1,Z; 18 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 19 inline void print(int x){ 20 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 21 while(z[++Z]=x%10+48,x/=10); 22 while(sr[++C]=z[Z],--Z);sr[++C]=' '; 23 } 24 const int N=60005,M=(1<<26)+5; 25 int a[N],rt[N],l,r,n,m,bl;char s[N]; 26 struct node{ 27 int l,r,id; 28 inline bool operator <(const node b)const 29 { 30 if(rt[l]!=rt[b.l]) return l<b.l; 31 return rt[l]&1?r<b.r:r>b.r; 32 } 33 }q[N]; 34 unsigned short c[M]; 35 int ans[N],ansn; 36 inline void add(int x){ 37 ansn+=c[a[x]]; 38 for(int i=0;i<26;++i) ansn+=c[a[x]^(1<<i)]; 39 ++c[a[x]]; 40 } 41 inline void del(int x){ 42 --c[a[x]]; 43 ansn-=c[a[x]]; 44 for(int i=0;i<26;++i) ansn-=c[a[x]^(1<<i)]; 45 } 46 int main(){ 47 n=read(),m=read(),bl=sqrt(n); 48 scanf("%s",s+1); 49 for(int i=1;i<=n;++i) a[i]=(1<<(s[i]-'a'))^a[i-1],rt[i]=(i-1)/bl+1; 50 for(int i=1;i<=m;++i) 51 q[i].l=read()-1,q[i].r=read(),q[i].id=i; 52 sort(q+1,q+1+m); 53 l=0,r=0,c[0]=1; 54 for(int i=1;i<=m;++i){ 55 while(l>q[i].l) add(--l); 56 while(r<q[i].r) add(++r); 57 while(l<q[i].l) del(l++); 58 while(r>q[i].r) del(r--); 59 ans[q[i].id]=ansn; 60 } 61 for(int i=1;i<=m;++i) print(ans[i]); 62 Ot(); 63 return 0; 64 }
然而实际上每一次都要做位运算太慢了,可以直接一波离散把所有能转移到的状态找出来,然后就会快很多(上面那个 7040ms,下面这个938ms)
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 inline int read(){ 8 #define num ch-'0' 9 char ch;bool flag=0;int res; 10 while(!isdigit(ch=getchar())) 11 (ch=='-')&&(flag=true); 12 for(res=num;isdigit(ch=getchar());res=res*10+num); 13 (flag)&&(res=-res); 14 #undef num 15 return res; 16 } 17 char sr[1<<21],z[20];int C=-1,Z; 18 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 19 inline void print(int x){ 20 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 21 while(z[++Z]=x%10+48,x/=10); 22 while(sr[++C]=z[Z],--Z);sr[++C]=' '; 23 } 24 const int N=60005,M=(1<<26)+5; 25 int a[N],b[N],rt[N],l,r,n,m,bl,ver[N*30],Next[N*30],head[N],tot;char s[N]; 26 struct node{ 27 int l,r,id; 28 inline bool operator <(const node b)const 29 { 30 if(rt[l]!=rt[b.l]) return l<b.l; 31 return rt[l]&1?r<b.r:r>b.r; 32 } 33 }q[N]; 34 unsigned short c[M]; 35 int ans[N],ansn; 36 inline void addedge(int u,int v){ 37 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 38 } 39 inline void add(int x){ 40 for(int i=head[a[x]];i;i=Next[i]) ansn+=c[ver[i]]; 41 ++c[a[x]]; 42 } 43 inline void del(int x){ 44 --c[a[x]]; 45 for(int i=head[a[x]];i;i=Next[i]) ansn-=c[ver[i]]; 46 } 47 int main(){ 48 //freopen("testdata.in","r",stdin); 49 n=read(),m=read(),bl=sqrt(n); 50 scanf("%s",s+1); 51 for(int i=1;i<=n;++i) b[i]=a[i]=(1<<(s[i]-'a'))^a[i-1],rt[i]=i/bl; 52 sort(b,b+1+n); 53 int k=unique(b,b+1+n)-b; 54 for(int i=0;i<k;++i){ 55 for(int j=0;j<26;++j){ 56 int t=b[i]^(1<<j); 57 int y=lower_bound(b,b+k,t)-b; 58 if(b[y]==t) addedge(i,y); 59 } 60 addedge(i,i); 61 } 62 for(int i=1;i<=n;++i) a[i]=lower_bound(b,b+k,a[i])-b; 63 for(int i=1;i<=m;++i) 64 q[i].l=read()-1,q[i].r=read(),q[i].id=i; 65 sort(q+1,q+1+m); 66 l=0,r=0,c[0]=1; 67 for(int i=1;i<=m;++i){ 68 while(l>q[i].l) add(--l); 69 while(r<q[i].r) add(++r); 70 while(l<q[i].l) del(l++); 71 while(r>q[i].r) del(r--); 72 ans[q[i].id]=ansn; 73 } 74 for(int i=1;i<=m;++i) print(ans[i]); 75 Ot(); 76 return 0; 77 }