LGP4495题解

第一眼看到题感觉有点儿怪。。。

先想一件事情:我们需要什么?

如果有一个物品的体积为 \(w\),那么令一个数不断地加上 \(w\),最后一定会回到 \(0\)

而对于一堆物品,一定存在一个 \(w\) 和这一堆物品等价。

容易发现,如果我取 \((P-1)\)\(w\) 相当于取了一个 \(-w\)。运用裴蜀定理可以知道这个 \(w\) 为这一堆物品的 \(\gcd\)

然后询问一个 \(p\) 关心的是有多少种方案凑成的 \(w\)\(p\) 的因数。

所以我们相当于要拿一堆数做一个 \(\gcd\) 背包。

容易发现另一件事,物品 \(w\) 和物品 \(\gcd(P,w)\) 等价。所以我们相当于是拿若干个数(不超过 \(1344\) 个)来做 \(\gcd\) 背包。于是把数填进桶之后莫反一下即可。

询问 \(p\) 时相当于询问 \(\gcd(P,p)\),只需要一遍 \(\gcd\) 即可。

莫反的过程有点儿像卷上一个 \(\mu\),所以大概是可以做到 \(O(\sigma(P)\omega(P)+q\log P)\),大不了 \(O(\sigma(P)^2+q\log P)\) 也是稳过的。

#include<algorithm>
#include<cstdio>
#include<cctype>
typedef unsigned ui;
const ui M=1350,mod=1e9+7;
ui n,q,P,m,p[35],k[35],K[35],f[M],id[M],val[M],vis[M];double inv[M];
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 Divide(ui n){
	for(ui i=2;i*i<=n;++i)if(!(n%i)){
		p[++m]=i;inv[m]=1./i+1e-15;while(!(n%i))++k[m],n/=i;
	}
	if(n^1)p[++m]=n,inv[m]=1./n+1e-15,k[m]=1;K[m+1]=1;for(ui i=m;i>=1;--i)K[i]=K[i+1]*(k[i]+1);
}
inline ui Getid(ui V){
	ui id(0);for(ui i=1;i<=m;++i)for(ui j(1);j<=k[i]&&V==ui(V*inv[i])*p[i];++j)id+=K[i+1],V*=inv[i];return id;
}
inline void DFS(const ui&n,ui V,const ui&tag,const ui&id){
	if(id==m+1)return vis[n]=tag,val[n]=V,void();
	for(ui i=0;i<=k[id];++i)DFS(n+i*K[id+1],V,tag|((i==k[id])<<id),id+1),V*=p[id];
}
inline ui read(){
	ui n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
inline void write(ui n){
	static char s[10];ui top(0);while(s[++top]=n%10^48,n/=10);while(putchar(s[top]),--top);putchar(10);
}
signed main(){
	n=read();q=read();P=read();Divide(P);
	while(n--)++f[Getid(read())];DFS(0,1,0,1);for(ui i=0;i<K[1];++i)id[i]=i;
	std::sort(id,id+K[1],[&](const ui&x,const ui&y){return val[x]<val[y];});
	for(ui i=1;i<=m;++i)for(ui x,j=K[1]-1;~j;--j)if(!(vis[x=id[j]]>>i&1))f[x]=(f[x]+f[x+K[i+1]])%mod;
	for(ui i=0;i<K[1];++i)f[i]=(pow(2,f[i])-1);
	for(ui i=1;i<=m;++i)for(ui x,j=0;j<K[1];++j)if(!(vis[x=id[j]]>>i&1))f[x]=(f[x]+mod-f[x+K[i+1]])%mod;
	for(ui i=1;i<=m;++i)for(ui x,j=0;j<K[1];++j)if(!(vis[x=id[j]]>>i&1))f[x+K[i+1]]=(f[x+K[i+1]]+f[x])%mod;
	while(q--)write(f[Getid(read())]);
}
posted @ 2022-04-18 14:48  Prean  阅读(17)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};