• P8292[省选联考 2022]卡牌【状压,容斥】


    正题

    题目链接:https://www.luogu.com.cn/problem/P8292


    题目大意

    \(n\)张卡牌,第\(i\)张上的数字是\(s_i\)\(m\)次询问给出\(c_i\)个质数,要求选择一些卡使得这些卡的乘积是这些质数的倍数,求方案数。

    \(1\leq n\leq 10^6,1\leq s_i\leq 2000,1\leq m\leq 1500,\sum_{i=1}^m c_i\leq 18000\)


    解题思路

    对于一个数字\(x\)来说,大于\(\sqrt x\)的质因子只会有一个,也就是对于大于所有的\(\sqrt s_i\)的质数\(p\),它们的倍数之间不会产生重复,可以分开计数。

    而小于\(\sqrt s_i\)的质数个数只有\(14\)个,我们可以考虑状压。

    处理出\(g_s\)表示在集合\(s\)中的质数都不选择(即没有这些数的倍数)时的数字个数,然后再预处理出一个\(f_{i,s}\)表示质数\(i\)的倍数中集合\(s\)中的质数都不选择时的数字个数。

    那么对于一个询问,我们先处理出小于等于\(\sqrt s\)的质数被加进去的状态\(S\),然后对于大于\(\sqrt s\)的每个质数\(p\),那么答案就是

    \[\sum_{T\sube S}\left(2^{g_T}\times \sum_{p}\left(1-\frac{1}{2^{f_{p,T}}}\right)\right)(-1)^{|T|} \]

    然后求和就可以了


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<cctype>
    #define ll long long
    using namespace std;
    const ll N=2100,M=1e6+10,L=14,P=998244353;
    ll n,m,cnt,pri[320],pw[M],iw[M],ct[1<<L];
    ll w[N],f[1<<L][320],g[1<<L],q[N*10],v[N];
    vector<ll> r;bool usd[N];
    ll read(){
    	ll x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    	return x*f;
    }
    void Prime(){
    	for(ll i=2;i<N;i++){
    		if(!v[i])pri[cnt]=i,cnt++,v[i]=cnt-1;
    		for(ll j=0;j<cnt&&i*pri[j]<N;j++){
    			v[i*pri[j]]=1;
    			if(i%pri[j]==0)break;
    		}
    	}
    	return;
    }
    signed main()
    {
    	Prime();
    	n=read();pw[0]=iw[0]=1;
    	for(ll i=1;i<=n;i++)pw[i]=pw[i-1]*2ll%P;
    	for(ll i=1;i<=n;i++)iw[i]=iw[i-1]*(P+1)/2ll%P;
    	for(ll i=1,x;i<=n;i++)x=read(),w[x]++;
    	ll MS=(1<<L);
    	for(ll s=1;s<MS;s++)ct[s]=ct[s-(s&-s)]+1;
    	for(ll s=0;s<MS;s++){
    		r.clear();
    		memset(usd,0,sizeof(usd));
    		for(ll i=0;i<L;i++)
    			if((s>>i)&1){
    				for(ll j=pri[i];j<=2000;j+=pri[i])
    					usd[j]=1;
    			}
    		for(ll i=1;i<=2000;i++)
    			if(!usd[i])g[s]+=w[i],r.push_back(i);
    		g[s]=pw[g[s]];
    		for(ll i=L;i<cnt;i++){
    			f[s][i]=0;
    			for(ll j=0;r[j]*pri[i]<=2000;j++)
    				f[s][i]+=w[r[j]*pri[i]];
    			ll k=f[s][i];
    			f[s][i]=iw[k]*(pw[k]-1)%P;
    		}
    	}
    	m=read();
    	while(m--){
    		ll k=read();
    		ll t=0,tot=0,ans=0;
    		for(ll i=1,x;i<=k;i++){
    			x=read();
    			if(v[x]<L)t|=1<<v[x];
    			else q[++tot]=v[x];
    		}
    		sort(q+1,q+1+tot);
    		tot=unique(q+1,q+1+tot)-q-1;
    		for(ll s=t;s>=0;s=(s-1)&t){
    			ll k=(ct[s]&1)?(P-g[s]):g[s];
    			for(ll i=1;i<=tot;i++)
    				k=k*f[s][q[i]]%P;
    			(ans+=k)%=P;
    			if(!s)break;
    		}
    		printf("%lld\n",(ans+P)%P);
    	}
    	return 0;
    }
    
  • 相关阅读:
    如何增加VM Ware虚拟机的硬盘空间
    安装完成oracle 11g R2 后,使用sqlplus 报错"sqlplus: error while loading shared libraries" ...
    listener.ora
    ExtJS项目框架有关问题讨论
    Oracle启动监听报错:The listener supports no services解决
    Linq学习笔记一
    PAT 1054 The Dominant Color[简单][运行超时的问题]
    Andrew NgML第十八章大规模机器学习
    PAT 1042 Shuffling Machine[难]
    PAT 1103 Integer Factorization[难]
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/16191815.html
Copyright © 2020-2023  润新知