关于 FWT 做法
查看原帖
关于 FWT 做法
174897
zjrdmd楼主2023/2/23 10:26
#include <bits/stdc++.h>

using namespace std;
const int N=2e5+5,mod=998244353;
void chkmax(int &x,int y){x=max(x,y);}
void chkmin(int &x,int y){x=min(x,y);}
void Add(int &x,int y){x+=y,x%=mod;}
int ab(int x){if(x<0)x=-x;return x;}
const int MB=1<<20;

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;
}
int n,m,a[1000005],c,p[N],mi_prim[N],mi[1000005],sum[N],sss[N],rk[N],ans,qwq;	
int f[2005][1<<14],g[1<<15],q[18005],ok[N],Inv[2005][1<<14],h[1<<15],inv[10000005],mx=10000000;
int prim[N],vis[N],cnt=0,b=42,tot=0;
vector<int>S[N];
//int lowbit(int x){
//	return x&(-x);
//} 
struct FastIO
{
	char ib[MB+100],*p,*q;
	char ob[MB+100],*r,stk[128];
	int tp;
	
	FastIO(){p=q=ib,r=ob,tp=0;}
	~FastIO(){fwrite(ob,1,r-ob,stdout);} //析构函数,自动flush 
	
	char read_char() //读入一个字符,注意会读入空白字符,例如空格换行
	{
		if(p==q)
		{
			p=ib,q=ib+fread(ib,1,MB,stdin);
			if(p==q)return 0;
		}
		return *p++;
	}
	template<typename T>
	void read_int(T& x) //读入一个整型变量,int,long long之类的都能读入 
	{
		char c=read_char(),l=0;
		for(x=0;!std::isdigit(c);c=read_char())l=c;
		for(;std::isdigit(c);c=read_char())x=x*10-'0'+c;
		if(l=='-')x=-x;
	}
	
	void write_char(char c) //输出一个字符 
	{
		if(r-ob==MB)r=ob,fwrite(ob,1,MB,stdout);
		*r++=c;
	}
	template<typename T>
	void write_int(T x) //输出一个整型变量,int,long long之类的都能输出 
	{
		if(x<0)write_char('-'),x=-x;
		do stk[++tp]=x%10+'0';
		while(x/=10);
		while(tp)write_char(stk[tp--]);
	}
}IO;
void Init(){
	for(int i=2;i<=2000;i++){
		if(!vis[i])prim[++cnt]=i,mi_prim[i]=i,rk[i]=cnt;
		for(int j=1;j<=cnt&&prim[j]*i<=2000;j++){
			vis[prim[j]*i]=1,mi_prim[prim[j]*i]=prim[j];
			if(i%prim[j]==0)break;
		}
	}
	for(int i=1;i<=2000;i++){
		int x=i;
		while((mi_prim[x]<=b)&&mi_prim[x])q[i]|=(1<<(rk[mi_prim[x]]-1)),x/=mi_prim[x];
		if(i==1849)S[43].push_back(i);
		else S[mi_prim[x]].push_back(i);
//		printf("%d %d\n",i,x);
	}
//	for(int i=1;i<=cnt;i++)printf("%d %d\n",i,mi_prim[i]);
}

void FWT(int *F){
	for(int i=0;i<13;i++)
		for(int s=0;s<(1<<13);s++)
			if(s&(1<<i))Add(F[s],F[s-(1<<i)]);
}
void IFWT(int *F){
	for(int i=12;i>=0;i--)
		for(int s=0;s<(1<<13);s++)
			if(s&(1<<i))Add(F[s],-F[s-(1<<i)]);
}
int kpow(int x,int y){
	if(!y)return 1;
	int res=kpow(x,y/2);
	if(y&1)return 1ll*res*res%mod*x%mod;
	else return 1ll*res*res%mod;
}
int main(){
//	freopen("card.in","r",stdin);
//	freopen("card.out","w",stdout); 
	inv[1]=1;
	for(int i=2;i<=mx;i++)inv[i]=((-1ll*(mod/i)*inv[mod%i]%mod)+mod)%mod;
	Init(),mi[0]=1;
	IO.read_int(n);
	for(int i=1;i<=n;i++)IO.read_int(a[i]),mi[i]=mi[i-1]*2%mod;
	for(int i=1;i<=n;i++)sum[a[i]]++,sss[a[i]]=sum[a[i]];
	for(int i=1;i<=2000;i++){
		for(int j=i+i;j<=2000;j+=i)sss[i]+=sss[j];
	}
	for(int i=0;i<=2000;i++){
		if((i>=b&&vis[i]==0)||i==0){
			tot+=sss[i];
			f[i][0]=1;
			for(int j=0;j<S[i].size();j++)//S[i]存所以最大质因子是i的数 
				for(int s=(1<<13)-1;s>=0;s--){
					Add(f[i][s|q[S[i][j]]],1ll*f[i][s]*(mi[sum[S[i][j]]]-1)%mod);
				}
			f[i][0]--;
			FWT(f[i]);
			for(int s=0;s<(1<<13);s++){
//				if(f[i][s]+1-lowbit(f[i][s]+1)!=0)printf("fuck\n");
				if(f[i][s]+1<=mx)Inv[i][s]=inv[f[i][s]+1];
				else Inv[i][s]=kpow(f[i][s]+1,mod-2);
			}
//			printf("%d\n",i);
		}
	}
	for(int s=0;s<(1<<13);s++)g[s]=f[0][s]+1;
	for(int i=2000;i>=b;i--){
		if(vis[i])continue;
		for(int s=0;s<(1<<13);s++)g[s]=1ll*g[s]*(f[i][s]+1)%mod;
	} 
	IO.read_int(m);
	while(m--){
		IO.read_int(c);
		for(int i=1;i<=c;i++)IO.read_int(p[i]),ok[p[i]]=1;
		sort(p+1,p+c+1);
		c=unique(p+1,p+c+1)-p-1;
		for(int s=0;s<(1<<13);s++)h[s]=g[s];
		for(int i=c;i>=1;i--){
			if(p[i]<b)continue;
			for(int s=0;s<(1<<13);s++)h[s]=1ll*h[s]*Inv[p[i]][s]%mod*f[p[i]][s]%mod;
		} 
		IFWT(h);
		int ans=0,g2=0;
		for(int i=1;i<=c;i++){
			if(p[i]>=b)break;
			g2|=(1<<(rk[p[i]]-1));
		}
		for(int s=0;s<(1<<13);s++){
			if((s&g2)==g2){
				Add(ans,h[s]);
			}
		}
		IO.write_int((ans+mod)%mod),IO.write_char('\n'); 
		for(int i=1;i<=c;i++)ok[p[i]]=0;
	} 
	return 0;
}
/*
10
912 273 1845 1441 105 488 1652 412 1537 962
20
8 61 3 41 5 2 59 29 7
9 61 3 19 59 13 103 131 7 41
12 3 11 131 5 41 7 29 53 61 37 103 2
5 131 103 11 59 19
1 7
1 41
1 5
1 29
1 59
1 59
1 59
1 7
1 131
1 11
1 37
1 2
1 3
1 29
1 37
1 3
*/ 

被卡常了,只有 85 ,复杂度瓶颈在于处理 ff 数组的时候需要算逆元,这里复杂度带 log。 有没有老哥知怎么卡常/去掉log。

2023/2/23 10:26
加载中...