洛谷P3604 美好的每一天(莫队)

传送门

 

由乃的题还是一如既往的可怕……

先放上原题解

标解:

一个区间可以重排成为回文串,即区间中最多有一个字母出现奇数次,其他的都出现偶数次

发现这个和  类似





这样如果一个区间的  和为  或者  ,则这个区间可以重排成为回文串,即回归天空

把每个位置的值变为前缀  和,那么区间  可以回归天空当且仅当  为  或者 

 即  的异或和

这样用莫队算法,可以做到  的复杂度

然后怎么用莫队?可以参考一下这道题目->异或序列

考虑区间$[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]='\n';
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]='\n';
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 }

 

posted @ 2018-08-26 19:57  bztMinamoto  阅读(315)  评论(0编辑  收藏  举报
Live2D