给出(a_i),对于集合(S),定义(f_0(S)=1)当且仅当存在任意钦定的系数(c_i),使得(sum_{iin S}a_ic_iequiv xpmod P),否则(f_0(S)=0)。
定义(f_i(S)=sum_{Tsubseteq S}f_{i-1}(T))。
求(f_k(U))。(U)为全集。
(Tle 20,nle 3*10^5)
(1le xle 10^{18}),(2le P le 10^{18}),(1le kle 10^9)
保证(P)的最大质因数小于等于(3*10^5)。
不可拍的题。。。
考虑第一部分:如何处理这个(f_0)。
以下先将(x)变成(xmod P)。
根据简单的数论知识,可以转化成如下问题:询问是否(gcd_{iin S}(gcd(a_i,P))|x)。原因大概根据式子(ax+by=gcd(a,b))得出。
为了方便,接下来直接把(gcd(a_i,P))替换成(a_i)。
分解质因数,这个东西相当于:对于某个质因数(p_i),存在(a_i),满足这个质因数在(a_i)的指数小于等于在(x)中的指数。
那么每个数可以用(01)串(b_i)来表示,其中第(j)位表示(p_j)的指数是否小于等于(x)中(p_j)的指数。
于是(f_0(S)=[or_{iin S} b_i=U'])。
想到这里再搞另一个问题:如何通过(f_0)得到(f_k)。
如果用集合幂级数来表示,发现就是(f_k=f_0*I^k)。
思考一下卷(I^k)是什么:先选出一个子集,在这个子集中选出一个子集,再选……选(k-1)遍((I)是只选自己而不是子集,所以是(k-1))。如果将选看成加一,那么最终每个数在([0,k-1])中随机,每个位置有(k)种选择。于是(I^k(S)=k^{|S|})。
于是(f_k(U)=sum_{S}f_0(S)k^{n-|S|}),提出(k^n),得到(f_k(U)=k^nsum_{S}f_0(S)k^{-|S|})。这启示着我们将(k^{-1})作为计算(f_0(S))时的系数。
回来思考一下(f_0(S))如何计算。列出式子:(f_0=prod (1+k^{-1}x^{b_i}))。发现(FWT(1+k^{-1}x^{b_i})(S)=1+k^{-1}[b_0subseteq S])。
一项对(FWT(f_0(S)))的贡献为在(b_0subseteq S)处给(f_0(S))乘(1+k^{-1})。于是只需要计算(1+k^{-1})的指数。
定义集合幂级数(g=sum {b_i}),(FWT(f_0)(S)=(1+k^{-1})^{FWT(g)(S)}),可以算出(g)再算出(f)。
于是这道题就结束了。实现的时候要注意一点细节(拍不出来……),并且卡卡常。
比如说给gcd
的速度是很慢的,这时候需要指数取(min)。还有在算(b_i)的时候可以加点剪枝。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 300005
#define ll long long
#define mo 1000000007
#define INF 1000000000
ll gcd(ll a,ll b){
while (b){
ll k=a%b;
a=b,b=k;
}
return a;
}
ll qpow(ll x,ll y=mo-2){
ll r=1;
for (;y;y>>=1,x=x*x%mo)
if (y&1)
r=r*x%mo;
return r;
}
int p[N],np;
bool inp[N];
void initp(int n){
for (int i=2;i<=n;++i){
if (!inp[i])
p[++np]=i;
for (int j=1;j<=np && i*p[j]<=n;++j){
inp[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
}
int n;
ll x,k,P;
ll a[N];
int b[N];
int c,d[17],e[17];
int idx(ll &n,int p){
if (n==0) return INF;
int t=0;
while (n%p==0)
n/=p,++t;
return t;
}
bool judge(ll &n,int p,int lim){
int t=0;
while (t<=lim && n%p==0)
n/=p,++t;
return t<=lim;
}
void divide(ll n){
c=0;
for (int i=1;i<=np && n!=1;++i)
if (n%p[i]==0){
d[c]=p[i];
e[c]=idx(n,p[i]);
c++;
}
if (n!=1)
d[c]=n,e[c]=1,c++;
}
void initb(){
static int bx[N];
ll xx=x;
for (int j=0;j<c;++j)
bx[j]=idx(xx,d[j]);
for (int i=1;i<=n;++i){
// ll ai=gcd(a[i],P);
ll ai=a[i];
b[i]=0;
// if (ai==0) continue;
for (int j=0;j<c;++j){
if (e[j]<=bx[j]){
b[i]|=1<<j;
continue;
}
if (judge(ai,d[j],bx[j]))
b[i]|=1<<j;
}
}
}
ll g[1<<17];
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int T;
scanf("%d%d",&n,&T);
for (int i=1;i<=n;++i)
scanf("%lld",&a[i]);
initp(300000);
while (T--){
scanf("%lld%lld%lld",&x,&k,&P);
x%=P;
divide(P);
initb();
// for (int i=1;i<=n;++i)
// printf("%d
",b[i]);
// printf("
");
memset(g,0,sizeof(ll)*(1<<c));
for (int i=1;i<=n;++i)
g[b[i]]++;
for (int i=1;i<1<<c;i<<=1)
for (int j=0;j<1<<c;j+=i<<1)
for (int k=0;k<i;++k)
g[j+k+i]+=g[j+k];
ll tmp=1+qpow(k);
for (int i=0;i<1<<c;++i)
g[i]=qpow(tmp,g[i]);
for (int i=1;i<1<<c;i<<=1)
for (int j=0;j<1<<c;j+=i<<1)
for (int k=0;k<i;++k)
(g[j+k+i]-=g[j+k])%=mo;
ll ans=(g[(1<<c)-1]+mo)%mo*qpow(k,n)%mo;
printf("%lld
",ans);
}
return 0;
}