gym103409H Popcount Words

数据范围很大啊...考虑对规律进行一个找并拆分成二进制
\(W_{n,0}=w(0,2^n-1),W_{n,1}=w(2^n,2^{n+1}-1)\)
则对于\(n>0\)\(W_{n,i}=W_{n-1,i}+W_{n-1,1-i},w_{k2^n,(k+1)2^n-1}=W_{n,popcount(k)\mod 2}\)
第一个式子可以给出一个递推关系,第二个式子可以把一个开头是\(k2^n\)长度为\(2^n\)的串拆下来
那么可以考虑将\(w_{l,r}\)拆分成二进制
具体方法是把每段区间按照左闭右开放到一个长度是\(\infty\)\(0-base\)线段树上,这样的话就能得到\(O(log)\)个区间满足\(l=k2^n,2^n|(r-l)\).
这样的话就得到了\(n\log V\)\(W_{n,i}\),考虑如何用它求出答案。
对于询问串建立AC自动机,这样一个串的答案就是它在AC自动机的fail树上的尾节点子树中原串的出现次数。
这个是可以dp的。
\(f_{u,n,i}\)表示u点经过\(W_{n,i}\)的终点,则对于\(n>0\)\(f_{u,n,i}=f_{f_{u,n-1,i},n-1,1-i}\)
但是我们要求的是出现次数而不是最终节点,所以转移时附带一个\(c_{u,n,i}\)表示直接使用\(W_{n,i}\)\(u\)转移的次数,
然后设\(g_{u,n,i}\)\(W_{n,i}\)直接加上间接在\(u\)点转移的次数则有:

\[g_{u,n,i}=c_{u,n,i}+g_{u,n+1,i}+\sum\limits_{f_{v,n+1,1-i}=u}g_{v,n+1,1-i} \]

那么对于一个点可以把它的\(g_{u,0,0/1}\)分别贡献给它的两个儿子表示它们的被访问次数.然后转移就完事了.
纸上谈兵没卵用,滚去写代码了

O3虽好,可不要贪杯哦

#pragma GCC optimize(3)
#include<vector>
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;
	#define pf printf
	#define F(i,a,b) for(int i=a;i<=b;i++)
	#define D(i,a,b) for(int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=5e5+10;
	int son[N][2],tot=1,L[N],R[N],fail[N],w[N][2],cnt,n,m,end[N],f[N][31][2],c[N][31][2];ll sum[N],now[N][2],nxt[N][2];char s[N];
	inline int insert(){
		int n=strlen(s+1),now=1;
		F(i,1,n){
			int v=s[i]-'0';
			if(!son[now][v])son[now][v]=++tot;
			now=son[now][v];
		}return now;
	}
	int q[N],hd=1,tl;
	inline void build(){
		F(i,0,1)son[0][i]=1;
		q[++tl]=1;
		while(hd<=tl){
			int x=q[hd++];
			F(i,0,1){
				int v=son[x][i];
				if(!v){son[x][i]=son[fail[x]][i];continue;}
				fail[v]=son[fail[x]][i];q[++tl]=v;
			}
		}
	}
	inline void build(int l,int r,int ql,int qr){
		if(ql>=r||l>=qr)return;
		if(l>=ql&&r<=qr){
			w[++cnt][0]=__builtin_ctz(r-l);
			w[cnt][1]=__builtin_popcount(l>>w[cnt][0])&1;
			return;
		}
		int mid=(l+r)>>1;
		build(l,mid,ql,qr);build(mid,r,ql,qr);
	}
	inline short main(){
		n=read(),m=read();
		F(i,1,n)L[i]=read(),R[i]=read();
		F(i,1,m){
			scanf("%s",s+1);
			end[i]=insert();
		}build();
		F(i,0,tot)f[i][0][0]=son[i][0],f[i][0][1]=son[i][1];
		F(j,1,30)F(i,0,tot)
			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];
		int Wow=1;
		F(i,1,n){
			cnt=0;
			build(0,1<<30,L[i],R[i]+1);
			F(j,1,cnt){
				c[Wow][w[j][0]][w[j][1]]++;
				Wow=f[Wow][w[j][0]][w[j][1]];
			}
		}
		D(n,29,0){
			memcpy(now,nxt,sizeof(now));
			memset(nxt,0,sizeof(nxt));
			F(u,1,tot)
				nxt[u][0]+=now[u][0]+c[u][n][0],
				nxt[u][1]+=now[u][1]+c[u][n][1],
				nxt[f[u][n][1]][0]+=now[u][1],
				nxt[f[u][n][0]][1]+=now[u][0];
		}
		F(i,1,tot)sum[son[i][0]]+=nxt[i][0],sum[son[i][1]]+=nxt[i][1];
		D(i,tot,1)sum[fail[q[i]]]+=sum[q[i]];
		F(i,1,m)pf("%lld\n",sum[end[i]]);
		return 0;
	}
}
signed main(){return EMT::main();}
posted @ 2022-04-27 11:37  letitdown  阅读(59)  评论(0编辑  收藏  举报