QOJ 6842
牛牛题。
首先看到一车模式串在一个文本串中的出现次数直接想到建出 AC 自动机。但是文本串实在太大,直接跑是不现实的。
首先注意到 \(w(0,2^n-1)\) 可以拆分成 \(w(0,2^{n-1}-1)+w(2^{n-1},2^{n}-1)\),且后者是前者的反转。
考虑求出 \(g_{i,j,0/1}\) 表示 AC 自动机上从点 \(i\) 经过 \(w(0,2^n-1)/w(2^n,2^{n+1}-1)\) 之后所到达的点,再求出 \(f_{i,j,0/1}\) 则表示跑文本串时这一段扫过的次数。
注意到任意一对 \([l_i,r_i]\) 都可以线段树式地拆分成 \(O(log\ V)\) 个区间,那么将模式串拆分后就可以直接在 AC 自动机上跑。
求出了 \(f_{i,j,0/1}\) 后考虑将其一路下放至 \(f_{i,j-1,0/1}\),直到最后的 \(f_{i,0,0/1}\),它表示了点 \(g_{i,0,0/1}\) 的经过次数。最后一遍 dfs 这题就做完了。
code
#include <bits/stdc++.h>
//taskkill /f /im 未命名1.exe
#define ED cerr<<endl;
#define TS cerr<<"I AK IOI"<<endl;
#define cr(x) cerr<<x<<endl;
#define cr2(x,y) cerr<<x<<" "<<y<<endl;
#define cr3(x,y,z) cerr<<x<<" "<<y<<" "<<z<<endl;
#define cr4(x,y,z,w) cerr<<x<<" "<<y<<" "<<z<<" "<<w<<endl;
#define print(a,l,r) for(int i=l;i<=r;++i) cerr<<a[i]<<' ';puts("");
#define popcnt __builtin_popcount
#define all(s) s.begin(),s.end()
#define bstring basic_string
//#define add(x,y) (x+=y)%=mod
#define pii pair<int,int>
#define epb emplace_back
#define pb push_back
#define mk make_pair
#define ins insert
#define fi first
#define se second
#define ll long long
//#define ull unsigned long long
using namespace std;
const int N=5e5+5,INF=2e9,mod=1e9+7;
int t,n,q;
char s[N];vector<pii> S;vector<int> e[N];
int tr[N][2],ne[N],id[N],idx=0;
ll f[N][31][2],ans[N];int g[N][31][2];
void Add(int l,int r,int L,int R) {
if(L<=l&&r<=R) {
S.epb(__lg(r-l+1),popcnt(l)&1);
return;
}
int mid=(l+r)>>1;
if(L<=mid) Add(l,mid,L,R);
if(R>mid) Add(mid+1,r,L,R);
}
void insert(char s[],int ID) {
int u=0;
for(int i=0;s[i];++i) {
int to=s[i]-'0';
if(!tr[u][to]) tr[u][to]=++idx;
u=tr[u][to];
}
id[ID]=u;
}
void build() {
queue<int> q;
for(int i=0;i<2;++i) {
if(tr[0][i]) q.push(tr[0][i]);
}
while(!q.empty()) {
int u=q.front();q.pop();
for(int i=0;i<2;++i) {
int c=tr[u][i];
if(!c) tr[u][i]=tr[ne[u]][i];
else {
ne[c]=tr[ne[u]][i];
q.push(c);
}
}
}
}
void dfs(int u) {
for(auto to:e[u]) {
dfs(to),ans[u]+=ans[to];
}
}
void sol() {
scanf("%d%d",&n,&q);
int l,r,all=(1<<30)-1;
for(int i=1;i<=n;++i) {
scanf("%d%d",&l,&r),Add(0,all,l,r);
}
for(int i=1;i<=q;++i) {
scanf("%s",s),insert(s,i);
}
build();
for(int i=0;i<=idx;++i) {
g[i][0][0]=tr[i][0];
g[i][0][1]=tr[i][1];
if(i) e[ne[i]].epb(i);
}
for(int i=1;i<=30;++i) {
for(int j=0;j<=idx;++j) {
g[j][i][0]=g[g[j][i-1][0]][i-1][1];
g[j][i][1]=g[g[j][i-1][1]][i-1][0];
}
}
int p=0;
for(auto it:S) {
int cnt=it.fi,op=it.se;
++f[p][cnt][op],p=g[p][cnt][op];
}
for(int i=30;i>=1;--i) {
for(int j=0;j<=idx;++j) {
f[j][i-1][0]+=f[j][i][0];
int to=g[j][i-1][0];
f[to][i-1][1]+=f[j][i][0];
f[j][i-1][1]+=f[j][i][1];
to=g[j][i-1][1];
f[to][i-1][0]+=f[j][i][1];
}
}
for(int i=0;i<=idx;++i) {
ans[tr[i][0]]+=f[i][0][0];
ans[tr[i][1]]+=f[i][0][1];
}
dfs(0);
for(int i=1;i<=q;++i) {
printf("%lld\n",ans[id[i]]);
}
}
int main()
{
t=1;
while(t--) {
sol();
}
return 0;
}