题目
给定一串字符串,询问多个区间,问有多少个子区间的字母经过移位后可以变成一个回文串
分析
那么回文串当且仅当s[r]s[r]s[r] xor s[l−1]=2ts[l-1]=2^ts[l−1]=2t or 0(s表示异或前缀和),也就是只含一个奇数次的字母或不含。
然后这些询问都支持离线,于是想到了莫队,但是莫队需要维护的是l−1∼rl-1\sim rl−1∼r,然后还要用分块优化,但是如何修改呢,可以记录区间内状态的个数,那答案为0就很好办了,那答案为2t(t为任意值)2^t(t为任意值)2t(t为任意值)怎么办,可以提前预处理,思路说完了,介绍坑点
unsigned short,啊啊啊啊
代码
#include <cstdio>
#include <cctype>
#include <queue>
#include <algorithm>
#include <cmath>
#define rr register
using namespace std;
typedef unsigned short ust;
struct rec{int l,r,rk,t;}b[60001];
ust w[1<<26]; bool v[1<<26];
int n,m,bk,now,f[60001][26],ans[60001],a[60001],len[60001];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
bool cmp(rec a,rec b){
return a.t<b.t||(a.t==b.t&&a.r<b.r);
}
inline void add(int x){
now+=w[a[x]],++w[a[x]];
for (rr int i=0;i<len[x];++i)
now+=w[f[x][i]];
}
inline void del(int x){
--w[a[x]],now-=w[a[x]];
for (rr int i=0;i<len[x];++i)
now-=w[f[x][i]];
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
signed main(){
n=iut(),m=iut(),v[0]=1,bk=n/sqrt(m),getchar();
for (rr int i=1;i<=n;++i)
v[a[i]=a[i-1]^(1<<(getchar()-97))]=1;
for (rr int i=0;i<=n;++i)
for (rr int j=0;j<26;++j)
if (v[a[i]^(1<<j)])
f[i][len[i]++]=a[i]^(1<<j);
for (rr int i=1;i<=m;++i) b[i]=(rec){iut(),iut(),i},b[i].t=b[i].l/bk;
sort(b+1,b+1+m,cmp); rr int l=b[1].l,r=b[1].l-1; ++w[a[l-1]];
for (rr int i=1;i<=m;++i){
while (l>b[i].l) add(--l-1);
while (r<b[i].r) add(++r);
while (l<b[i].l) del(l-1),++l;
while (r>b[i].r) del(r),--r;
ans[b[i].rk]=now;
}
for (rr int i=1;i<=m;++i) print(ans[i]),putchar(10);
return 0;
}