正题
题目链接:https://www.luogu.com.cn/problem/P8292
题目大意
有
n
n
n张卡牌,第
i
i
i张上的数字是
s
i
s_i
si?。
m
m
m次询问给出
c
i
c_i
ci?个质数,要求选择一些卡使得这些卡的乘积是这些质数的倍数,求方案数。
1
≤
n
≤
1
0
6
,
1
≤
s
i
≤
2000
,
1
≤
m
≤
1500
,
∑
i
=
1
m
c
i
≤
18000
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
1≤n≤106,1≤si?≤2000,1≤m≤1500,∑i=1m?ci?≤18000
解题思路
对于一个数字
x
x
x来说,大于
x
\sqrt x
x
?的质因子只会有一个,也就是对于大于所有的
s
i
\sqrt s_i
s
?i?的质数
p
p
p,它们的倍数之间不会产生重复,可以分开计数。
而小于
s
i
\sqrt s_i
s
?i?的质数个数只有
14
14
14个,我们可以考虑状压。
处理出
g
s
g_s
gs?表示在集合
s
s
s中的质数都不选择(即没有这些数的倍数)时的数字个数,然后再预处理出一个
f
i
,
s
f_{i,s}
fi,s?表示质数
i
i
i的倍数中集合
s
s
s中的质数都不选择时的数字个数。
那么对于一个询问,我们先处理出小于等于
s
\sqrt s
s
?的质数被加进去的状态
S
S
S,然后对于大于
s
\sqrt s
s
?的每个质数
p
p
p,那么答案就是
∑
T
?
S
(
2
g
T
×
∑
p
(
1
?
1
2
f
p
,
T
)
)
(
?
1
)
∣
T
∣
\sum_{T\sube S}\left(2^{g_T}\times \sum_{p}\left(1-\frac{1}{2^{f_{p,T}}}\right)\right)(-1)^{|T|}
T?S∑?(2gT?×p∑?(1?2fp,T?1?))(?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;
}
|