GYM103409H Popcount Words 题解
先来三个科技给大家介绍一下:
__builtin_ctz(x)
这表示\(x\)的后缀的\(0\)的个数。
__builtin_clz(x)
这表示\(x\)前缀的\(0\)的个数。(unsigned int 下)
__builtin_parity(x)
这表示\(x\)在二进制下\(1\)的个数的奇偶性。
首先我们容易观察得到,定义\(w_1(l,r)\)表示\(w(l,r)\)反过来的结果,那么\(w(0,2^i-1)=w(0,2^{i-1}-1)+w_1(0,2^{i-1}-1)\),证明考虑前\(2^{i-1}\)个数第\(2^{i-1}\)位为\(0\),后\(2^{i-1}\)个数这些位置为\(1\),其余位置不变,(下文把\(w_0(l,r)\)和\(w(l,r)\)视为等价)。这启发我们可以把\(w(l,r)\)拆成\(2\log_2(r-l+1)\)个区间进行运算(相同的高位可以忽略不计),套路的对模式串建出AC自动机,那么我们要求的就是每一个节点及其\(fail\)子树的遍历次数的和,我们注意到我们可以快速计算出\(f_{i,j,k}\)表示第\(i\)个位置在经历\(w(0,2^j-1)_k\)后所变成的结果。然后我们可以定义\(g_{i,j,k}\)表示从第\(i\)个位置发出\(w(0,2^j-1)_k\)的个数,我们可以利用上面的性质进行转移,容易发现\(g_{i,j-1,k}\)和\(g_{f_{i,j-1,k},j-1,k\oplus1}\)组成了\(g_{i,j,k}\),我们可以先标记,然后花费\(O(q\log_2V)\)的次数把标记下放到\(g_{i,0,0/1}\),然后就可以轻松处理出每一个点被经过的次数,放到\(fail\)树上跑一下就可以看出来答案了。(实在看不懂的看代码)
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
long long ans[maxn],g[maxn][40][2];
int f[maxn][40][2],ch[maxn][2],fail[maxn],ed[maxn],n,m,x[maxn],y[maxn],l,r,now,tot;
vector<int>tu[maxn];
queue<int>Q;
string s;
int insert(){
now=0;
for(int i=0;i<s.size();i++){
if(!ch[now][s[i]-'0']){
tot++;
ch[now][s[i]-'0']=tot;
}
now=ch[now][s[i]-'0'];
}
return now;
}
void dfs(int q){
for(int i=0;i<tu[q].size();i++){
dfs(tu[q][i]);
ans[q]+=ans[tu[q][i]];
}
return;
}
int lowbit(int q){
return q&(-q);
}
void getfail(){
for(int i=0;i<2;i++){
if(ch[0][i]){
Q.push(ch[0][i]);
}
}
while(!Q.empty()){
now=Q.front();
Q.pop();
tu[fail[now]].push_back(now);
for(int i=0;i<2;i++){
if(!ch[now][i]){
ch[now][i]=ch[fail[now]][i];
}
else{
fail[ch[now][i]]=ch[fail[now]][i];
Q.push(ch[now][i]);
}
}
}
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
}
for(int i=1;i<=m;i++){
cin>>s;
ed[i]=insert();
}
getfail();
for(int i=0;i<=tot;i++){
f[i][0][0]=ch[i][0];
f[i][0][1]=ch[i][1];
}
for(int j=1;j<=29;j++){
for(int i=0;i<=tot;i++){
f[i][j][0]=f[f[i][j-1][0]][j-1][1];
f[i][j][1]=f[f[i][j-1][1]][j-1][0];
}
}
now=0;
for(int i=1;i<=n;i++){
l=x[i];
r=y[i]+1;
while(l+lowbit(l)<r){
g[now][__builtin_ctz(l)][__builtin_parity(l)]++;
now=f[now][__builtin_ctz(l)][__builtin_parity(l)];
l+=lowbit(l);
}
while(l<r){
g[now][31-__builtin_clz(r-l)][__builtin_parity(l)]++;
now=f[now][31-__builtin_clz(r-l)][__builtin_parity(l)];
l+=1u<<(31-__builtin_clz(r-l));
}
}
for(int j=28;j>=0;j--){
for(int i=0;i<=tot;i++){
g[i][j][0]+=g[i][j+1][0];
g[i][j][1]+=g[i][j+1][1];
g[f[i][j][0]][j][1]+=g[i][j+1][0];
g[f[i][j][1]][j][0]+=g[i][j+1][1];
}
}
for(int i=0;i<=tot;i++){
ans[ch[i][0]]+=g[i][0][0];
ans[ch[i][1]]+=g[i][0][1];
}
dfs(0);
for(int i=1;i<=m;i++){
cout<<ans[ed[i]]<<'\n';
}
return 0;
}
浙公网安备 33010602011771号