Newcoder 39 F.重排的回文串(莫队算法+位运算)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/V5ZSQ/article/details/83302071

Description

给一个长为 n n 的只含小写字母的字符串

每次查询一个区间$ [l,r]$ 内,有多少子区间可以重排为一个回文串

一个区间可以重排为一个回文串:

就是说我们可以以一定顺序排列这个区间内的所有数使得排列后为一个回文串

Input

第一行两个正整数 n , m n,m

第二行一个长为 n n 的字符串

之后 m m 行每行两个数$ l$ 和$ r$

( n , m 6 1 0 4 ) (n,m\le 6\cdot 10^4)

Output

扫描二维码关注公众号,回复: 3897338 查看本文章

对于每个询问,输出一个整数表示答案

Sample Input

6 5
zzqzzq
2 4
3 4
2 3
4 5
1 1

Sample Output

4
2
2
3
1

Solution

只需考虑区间中每个字母的奇偶性,显然只能至多一种字母出现奇数次,由于字符串只由小写字母组成,用 26 26 01 01 来表示每种字母的奇偶性,假设 S i S_i 表示长度为 i i 的前缀的字母状态,那么区间 [ l , r ] [l,r] 合法当且仅当 S r = S l 1 S_r=S_{l-1} S l 1 S r S_{l-1}\oplus S_r 2 2 的整数次幂,其中 \oplus 表示异或运算,故可以用莫队维护区间中每种状态 S i S_i 的出现次数,每次可以 O ( 26 ) O(26) 的更新答案和 O ( 1 ) O(1) 的维护,为此需要对 S i S_i 离散化编号,以及对每个 r r 预处理可能合法的 l 1 l-1 ,总时间复杂度 O ( 26 n n ) O(26n\sqrt{n})

Code

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=60005;
struct node
{
    int l,r,id;
}q[maxn];
int n,m,h[maxn],c[maxn],d[maxn],pos[maxn],num[maxn];
char s[maxn];
vector<int>f[maxn];
ll res,ans[maxn];
int cmp(node x,node y)
{
    if(pos[x.l]!=pos[y.l])return x.l<y.l;
    return x.r<y.r;
}
void update(int x,int v)//表示对第x个元素做删除(v=-1)或者添加(v=1) 
{
    if(v==1)
    {
    	res+=num[d[x]];
    	for(int i=0;i<f[x].size();i++)res+=num[f[x][i]];
    	num[d[x]]++;
    }
    else
    {
    	num[d[x]]--;
    	res-=num[d[x]];
    	for(int i=0;i<f[x].size();i++)res-=num[f[x][i]];
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int mm=(int)sqrt(n);
    pos[0]=0;
    for(int i=1;i<=n;i++)pos[i]=(i-1)/mm+1;
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
    {
    	s[i]-='a';
    	c[i]=c[i-1]^(1<<s[i]);
    	h[i]=c[i];
    }
    h[0]=0;
    sort(h,h+n+1);
    int nn=unique(h,h+n+1)-h;
    for(int i=1;i<=n;i++)d[i]=lower_bound(h,h+nn,c[i])-h;
    for(int i=0;i<=n;i++)
    	for(int j=0;j<26;j++)
    	{
    		int pos=lower_bound(h,h+nn,c[i]^(1<<j))-h;
    		if(pos<nn&&h[pos]==(c[i]^(1<<j)))f[i].push_back(pos);
    	}
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].l--;
        q[i].id=i;
    }
    sort(q,q+m,cmp);
    res=0;
    int l=0,r=-1;
    for(int i=0;i<m;i++)
    {
        while(r<q[i].r)update(r+1,1),r++;
        while(r>q[i].r)update(r,-1),r--;
        while(l<q[i].l)update(l,-1),l++;
        while(l>q[i].l)update(l-1,1),l--;
        ans[q[i].id]=res; 
    }
    for(int i=0;i<m;i++)printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/V5ZSQ/article/details/83302071
39