1 条题解

  • 0
    @ 2025-8-24 21:50:39

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar juju527
    **

    搬运于2025-08-24 21:50:39,当前版本为作者最后更新于2020-03-27 20:29:55,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    莫队

    注意到回文串只可能是所有字母都是偶数个或者仅有一个字母是奇数个

    由于区间内我们只关心字母的奇偶,想到异或

    对于一个区间我们用一个26位的二进制数表示每一个字母出现次数为奇或偶(0偶1奇)

    而我们只要把所有的前缀区间的状态计算出来,对于任意一个区间我们都可以异或得到答案

    定义aia_i表示区间[1,i]的各个字母出现状态的值

    [x,y]的状态即ayax1a_y\bigoplus a_{x-1}

    那么其实原问题就被我们转换成对于一个区间[x,y]

    选择i属于[x-1,y]的两个不同位置的a值进行异或是否能得到0或者2的某次方

    得到0即字母都是奇数个,2的某次方即仅有一个字母是奇数个

    我们考虑莫队区间拓展的过程

    进来一个值时相当于多了一个a值x可用

    根据异或的传递性,我们查询原本这个区间里a值等于x的有多少和a值等于x异或2的某次方的有多少

    删除同理

    复杂度O(26nn)O(26*n\sqrt n)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=60005,maxm=60005;
    int n,m;
    int base;
    struct query{
    	int id;
    	int x,y;
    	bool operator <(query i)const{
    		return x/base==i.x/base?y<i.y:x<i.x;
    	}
    }q[maxm];
    int ans=0;
    int a[maxn];
    int cnt[(1<<26)+5];
    int ANS[maxm];
    inline int read(){
    	register int x=0,y=1;
    	register char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    	return x*y;
    }
    inline void ins(register int x){
    	ans+=cnt[a[x]];
    	cnt[a[x]]++;
    	for(register int i=0;i<26;i++)
    		ans+=cnt[a[x]^(1<<i)];
    	return ;
    }
    inline void del(register int x){
    	cnt[a[x]]--;
    	ans-=cnt[a[x]];
    	for(register int i=0;i<26;i++)
    		ans-=cnt[a[x]^(1<<i)];
    	return ;
    }
    int main(){
    	n=read();m=read();
    	base=3*sqrt(n);
    	for(register int i=1;i<=n;i++){
    		register char c;
    		cin>>c;
    		a[i]=1<<(c-'a');
    		a[i]^=a[i-1];
    	}
    	for(register int i=1;i<=m;i++){
    		q[i].id=i;
    		q[i].x=read();
    		q[i].y=read();
    	}
    	sort(q+1,q+m+1);
    	int l=1,r=0;
    	for(register int i=1;i<=m;i++){
    		register int x=q[i].x-1,y=q[i].y,id=q[i].id;
    		while(l<x)del(l++);
    		while(l>x)ins(--l);
    		while(r>y)del(r--);
    		while(r<y)ins(++r);
    		ANS[id]=ans;
    	}
    	for(register int i=1;i<=m;i++)printf("%d\n",ANS[i]);
    	return 0;
    }
    
    
    • 1

    信息

    ID
    2676
    时间
    3000ms
    内存
    159MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者