BZOJ 4866 [Ynoi2017]由乃的商场之旅
题解:
把每个字母表示成二进制
令sum[i]表示i的前缀异或
则一个区间是合法的条件是异或和=0或只有一位是1
上莫队,然后T了
优化先留个坑
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=60009;
const int SIZ=400;
const int u=26;
int n,m;
char ss[maxn];
int a[maxn]={0};
int s[maxn]={0};
int ql[maxn],qr[maxn],p[maxn];
long long ans[maxn];
bool cmp(const int &rhs1,const int &rhs2){
if(ql[rhs1]/SIZ==ql[rhs2]/SIZ){
return qr[rhs1]<qr[rhs2];
}else{
return ql[rhs1]<ql[rhs2];
}
}
unsigned short tong[1<<26]={0};
int Cal(int x){
int ret=tong[x];
for(int i=1;i<=26;++i){
ret+=tong[x^(1<<(i-1))];
}
return ret;
}
int main(){
scanf("%d%d",&n,&m);
scanf("%s",ss+1);
for(int i=1;i<=n;++i)a[i]=(1<<(ss[i]-'a'));
for(int i=1;i<=n;++i)s[i]=s[i-1]^a[i];
for(int i=1;i<=m;++i)scanf("%d%d",&ql[i],&qr[i]);
for(int i=1;i<=m;++i)--ql[i];
for(int i=1;i<=m;++i)p[i]=i;
sort(p+1,p+1+m,cmp);
long long nowans=0;
int p1=1,p2=0;
for(int i=1;i<=m;++i){
int t=p[i];
int l=ql[t],r=qr[t];
while(p1>l){
--p1;
nowans+=Cal(s[p1]);
++tong[s[p1]];
}
while(p2<r){
++p2;
nowans+=Cal(s[p2]);
++tong[s[p2]];
}
while(p1<l){
--tong[s[p1]];
nowans-=Cal(s[p1]);
++p1;
}
while(p2>r){
--tong[s[p2]];
nowans-=Cal(s[p2]);
--p2;
}
ans[t]=nowans;
}
for(int i=1;i<=m;++i)printf("%lld\n",ans[i]);
return 0;
}
致歉:笔者已经意识到这是一篇几乎没有价值的文章,给您的阅读带来不好的体验,并且干扰了您的搜索环境,非常抱歉!

浙公网安备 33010602011771号