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; }
致歉:笔者已经意识到这是一篇几乎没有价值的文章,给您的阅读带来不好的体验,并且干扰了您的搜索环境,非常抱歉!