洛谷P4495 [HAOI2018]奇怪的背包(数论)

题面

传送门

题解

好神仙的思路啊……orzyyb

因为不限次数,所以一个体积为\(V_i\)的物品可以表示出所有重量为\(\gcd(V_i,P)\)的倍数的物品,而所有物品的总和就是这些所有的\(\gcd\)

那么我们把每个\(V_i\)转化为\(\gcd(V_i,P)\),把\(w_i\)转化为\(\gcd(w_i,P)\),题目就可以变成问有多少种选择\(V_i\)的方法使\(V_i\)\(\gcd\)\(w_i\)的因子

据说当\(P\)很大的时候\(\sigma(P)\)大概只有\(P^{1\over 3}\)的数量级,那么我们可以对于\(P\)的所有的因数预处理答案,到时候就可以\(O(\log P)\)回答了(这里的\(\log\)是求\(\gcd\)的复杂度)

我们设\(f_i\)表示所有数的\(\gcd\)\(i\)的方案数,如果有\(s\)个数是\(i\)的倍数,那么方案数就是\(2^s-1\),然后再减去所有\(\gcd\)\(i\)的倍数的方案就行了

复杂度为\(O((n+q)\log q+\sigma^2(q))\)

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e6+5,M=50005,P=1e9+7;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
	return res;
}
int gcd(int x,int y){return y?gcd(y,x%y):x;}
int id1[M],id2[M],f[M],s[M],st[M],w[M],a[N],bin[N];
int n,q,p,tot,top,res,x;
inline int ID(R int x){return x<M?id1[x]:id2[p/x];}
int main(){
//	freopen("testdata.in","r",stdin);
	n=read(),q=read(),p=read();
	fp(i,1,n)a[i]=gcd(p,read());
	bin[0]=1;fp(i,1,n)bin[i]=mul(bin[i-1],2);
	fp(i,1,sqrt(p))if(p%i==0){
		w[++tot]=i;
		p/i!=i?w[++tot]=p/i:0;
	}
	sort(w+1,w+1+tot);
	fp(i,1,tot)w[i]<M?id1[w[i]]=i:id2[p/w[i]]=i;
	fp(i,1,n)++s[ID(a[i])];
	fd(i,tot,1){
		res=top=0;
		fp(j,i,tot)w[j]%w[i]==0?(st[++top]=j,res+=s[j]):0;
		f[i]=bin[res]-1;
		fp(j,2,top)f[i]=dec(f[i],f[st[j]]);
	}
	fd(i,tot,1)fp(j,1,i-1)w[i]%w[j]==0?f[i]=add(f[i],f[j]):0;
	while(q--)x=gcd(p,read()),print(f[ID(x)]);
	return Ot(),0;
}
posted @ 2019-03-13 08:16  bztMinamoto  阅读(201)  评论(0编辑  收藏  举报
Live2D