P3604 美好的每一天 题解

以下 \(V\) 代表字符集大小,此题为 \(26\)

Sol

我们可以联想到:一个串回文的充要条件是出现次数为奇数的字符个数 \(\le 1\),由于我们只在乎奇偶性,于是可以状压。

具体的,二进制下第 \(0\) 位代表 a 出现的奇偶性,第 \(1\) 位代表 b 出现的奇偶性,以此类推。

我们令 \(sum_i\) 表示字符串前 \(i\) 个位置的字母出现的奇偶性,这样的话我们就可以 \(O(1)\) 判断一个区间是否是回文串。

具体的,如果要判断 \([l,r]\) 是否回文,只需要判断 \(sum_r\) 异或 \(sum_{l-1}\) 在二进制下 \(1\) 的个数即可。

但如果要统计,需要 \(O(V)\) 的时间复杂度,对于每个新加进来的 \(val\),不断统计它异或上 \(2^k\) 的个数和它自己的个数即可。

于是这题就变成了一个统计性问题,可以用莫队解决。

总时间复杂度 \(O(qV\sqrt{n})\),空间复杂度 \(O(2^V)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long 

inline int read()
{
    int x(0);
    char ch(getchar());
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x;
}

const int N=1e5+5,C=26;
int n,m,sqn,ans[N],answ,cnt[1ll<<C],a[N];
class Node
{
public:
    int lt,rt,ip;
    bool operator<(const Node& tmp)const
    {
        if(lt/sqn!=tmp.lt/sqn)
            return lt<tmp.lt;
        return rt<tmp.rt;
    }
}q[N];
string s;

inline void add(int val)
{
    answ+=cnt[val];
    cnt[val]++;
    for(int i=0;i<C;i++)
        answ+=cnt[val^(1ll<<i)];
    return ;
}

inline void del(int val)
{
    cnt[val]--;
    answ-=cnt[val];
    for(int i=0;i<C;i++)
        answ-=cnt[val^(1ll<<i)];
    return ;
}

signed main()
{
    n=read(),m=read();
    cin>>s;
    s=" "+s;
    sqn=sqrt(n);
    for(int i=1;i<=n;i++)
        a[i]=a[i-1]^(1ll<<(s[i]-'a'));
    for(int i=1;i<=m;i++)
        q[i].lt=read()-1,q[i].rt=read(),q[i].ip=i;
    sort(q+1,q+m+1);
    int lt=0,rt=-1;
    for(int i=1;i<=m;i++)
    {
        while(rt<q[i].rt)
            add(a[++rt]);
        while(q[i].lt<lt)
            add(a[--lt]);
        while(q[i].rt<rt)
            del(a[rt--]);
        while(lt<q[i].lt)
            del(a[lt++]);
        ans[q[i].ip]=answ;
    }
    for(int i=1;i<=m;i++)
        cout<<ans[i]<<"\n";
    return 0;
}

posted @ 2025-05-05 20:02  tmp_get_zip_diff  阅读(13)  评论(0)    收藏  举报