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;
}

浙公网安备 33010602011771号