LGP8292口胡

场外选手口胡

如果对质因子这方面熟悉的可以看出来,相当于是我有一车集合,每次给定一个集合,问你有多少种方法选择若干集合使得或起来为给定集合。

首先传统艺能压状态数,将 \(n=\prod p^k\) 全部变为 \(n=\prod p\),很明显不影响。我们将相同的数丢到一个桶里面。然后将这个数的权值变为 \(2^{cnt}-1\)

然后观察到值域只有 \(2000\),开个根号是 \(44\)\(44\) 以内的质数数量非常少(\(14\) 个),所以传统艺能状压。对于每个数我们也拿出其最大质因子,然后将这个数挂在上面。最大质因子不大于 \(44\) 的数全部挂在一起。

剩下的部分就是或背包了。可以用 FWT 解决。

实现的时候可以考虑挂在一起的数全部先卷一遍,然后维护成点值,一起乘起来。

复杂度是 \(O(V2^{14}\times 14+n+\sum c_i2^{14}+m2^{14}\times 14)\),可以通过。

可以优化到 \(O(V2^{13}+n+\sum c_i2^{13}+m2^{13})\),偷懒写的 \(O(V2^{13}+n+\sum c_i2^{13}+m2^{13}\times 13)\)

等什么时候有数据了写出来测一下吧。。。鸽了

upd:写的时候忘记判 \(s_i=1\) 拿了 30,然后判了之后 lg 最大点 800ms。。。如果我上了考场真的能行吗。。。

#include<cstring>
#include<cstdio>
#include<cctype>
#define clr(F) memset(F,0,1<<15)
#define cpy(F,G) memcpy(F,G,1<<15)
typedef unsigned ui;
const ui M=1<<13,mod=998244353;
ui n,m,q,CB[2005],g[M],h[M],f[305][M];ui id[2005],pos[2005],mxp[2005];ui top,pri[305];
bool V[2005],vis[2005];char buf[1<<26|1],*_P=buf;
inline void swap(ui&a,ui&b){
	ui c=a;a=b;b=c;
}
inline ui pow(ui a,ui b=mod-2){
	ui ans(1);for(;b;b>>=1,a=1ull*a*a%mod)if(b&1)ans=1ull*ans*a%mod;return ans;
}
inline void px(ui*f,ui*g){
	for(ui k=0;k^M;++k)f[k]=1ull*f[k]*g[k]%mod;
}
inline void sieve(){
	for(ui i=2;i<=2000;++i){
		if(!id[i])id[i]=i,pri[pos[i]=++top]=i;
		for(ui x,j=1;j<=pos[i]&&(x=i*pri[j])<=2000;++j)id[x]=id[i]*((pos[x]=j)==pos[i]?1:pri[j]);
	}
	for(ui i=2;i<=2000;++i)if(id[i]==i)mxp[i]=pri[pos[i]]==i?pos[i]:mxp[i/pri[pos[i]]];
	for(ui i=1;i<=2000;++i)if(mxp[i])mxp[i]=mxp[i]>13?mxp[i]-12:1;
	m=top-12;
}
inline void GetInv(ui*f){
	static ui S[M];ui inv;S[0]=f[0];
	for(ui k=1;k^M;++k)S[k]=1ull*S[k-1]*f[k]%mod;inv=pow(S[M-1]);
	for(ui k=M-1;k;--k)S[k]=1ull*inv*S[k-1]%mod,inv=1ull*inv*f[k]%mod;S[0]=inv;
	for(ui k=0;k^M;++k)f[k]=S[k];
}
inline ui read(){
	ui n(0);char s;while(!isdigit(s=*_P++));while(n=n*10+(s&15),isdigit(s=*_P++));return n;
}
signed main(){
	fread(buf,1,1<<26,stdin);
	sieve();n=read();while(n--)++CB[id[read()]];q=read();
	for(ui i=1;i<=m;++i)for(ui k=0;k^M;++k)f[i][k]=1;for(ui k=0;k^M;++k)g[k]=1;
	for(ui i=1;i<=2000;++i)if(CB[i]){
		ui S(0);const ui&c=pow(2,CB[i]);for(ui k=1;k<=13;++k)if(!(i%pri[k]))S|=1<<k-1;
		for(ui k=0;k^M;++k)if((k&S)==S)f[mxp[i]][k]=1ull*f[mxp[i]][k]*c%mod;
	}
	for(ui i=1;i<=m;++i){
		cpy(h,f[i]);px(g,h);GetInv(h);for(ui k=0;k^M;++k)f[i][k]=(mod+f[i][k]-1)%mod;px(f[i],h);
	}
	while(q--){
		static ui ans[M];ui k=read();cpy(ans,g);
		for(ui p,i=1;i<=k;++i)p=read(),V[pos[p]]=true,vis[mxp[p]]=true;
		for(ui i=2;i<=m;++i)if(vis[i])px(ans,f[i]);
		for(ui len=1;len^M;len<<=1)for(ui i=0;i^M;i+=len<<1)for(ui k=0;k^len;++k){
			ans[i|k|len]=(ans[i|k|len]+mod-ans[i|k])%mod;
		}
		ui S(0),sum(0);for(ui k=1;k<=13;++k)if(V[k])S|=1<<k-1;
		for(ui k=0;k^M;++k)if((k&S)==S)sum=(sum+ans[k])%mod;
		for(ui k=0;k<=2000;++k)V[k]=vis[k]=false;
		printf("%u\n",1ull*sum*pow(2,CB[0])%mod);
	}
}
posted @ 2022-04-17 14:23  Prean  阅读(27)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};