正题
题目链接:https://www.51nod.com/Contest/Problem.html#contestProblemId=1149
题目大意
nnn个数,求有多少种选择方案使选择的数乘机为kkk。
解题思路
显然kkk的质因数最多只有999个,我们将质因数进行dpdpdp。若选择的数的质因数刚好是kkk的质因数,那么就可以。
为了方便我们将状态压成一维的即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1100,XJQ=1e9+7;
struct node{ll w,v;
}q[N];
bool cmp(node x,node y)
{return x.w<y.w;}
ll n,K,v[N],sum[N],f[N*N],T,cnt,two;
void dfs(ll x,ll s,ll zs)
{if(x>cnt){(f[zs]+=f[s])%=XJQ;return;}for(ll i=q[x].v-v[x];i>=0;i--)dfs(x+1,s+sum[x-1]*i,zs+sum[x-1]*(i+v[x]));
}
int main()
{scanf("%lld",&T);while(T--){scanf("%lld%lld",&n,&K);cnt=0;for(ll i=2;i*i<=K;i++){if(!(K%i)){q[++cnt].w=i;q[cnt].v=0;while(!(K%i))q[cnt].v++,K/=i;}}if(K!=1) q[++cnt].w=K,q[cnt].v=1;sort(q+1,q+1+cnt,cmp);memset(f,0,sizeof(f));f[0]=sum[0]=two=1;for(ll i=1;i<=cnt;i++)sum[i]=sum[i-1]*(q[i].v+1);for(ll i=1;i<=n;i++){ll x=0,z=0,l=0,r=1;bool flag=0;scanf("%lld",&x);if(x==1){two=two*2%XJQ;continue;}memset(v,0,sizeof(v));for(ll j=2;j*j<=x;j++){if(!(x%j)){while(q[l].w<j) r*=v[l],l++;if(q[l].w!=j){flag=1;break;}while(!(x%j))x/=j,v[l]+=(q[l].w==j);if(v[l]>q[l].v){flag=1;break;}}}if(flag) continue;if(x!=1){for(l=0,r=1;q[l].w<x;r*=v[l],l++);if(q[l].w==x)v[l]++;}dfs(1,0,0);}printf("%lld\n",(f[sum[cnt]-1]*two)%XJQ);}
}