题意:给定一个长度为n,要求乘积为m,其中组成m的数要求是整数
思路:首先有个很显然的想法:设表示前i个点乘积为j的最小值。因为询问数很多,所以必须离线把所有的东西都处理出来。
转移:,考虑道空间会爆,所以可以把1先不考虑。
那么相乘次数就不会超过20次,是log级别的。
对于负数而言,手玩一下发现是的。
对于1而言,设每个非1的位置为k,那么就有k+1个空间给1插入。
所以考虑插板法,如果有N个数插入M个空间:
1.每个空间至少插1个数:
2.每个空间最少插0个数:
其中:,
所以贡献是
复杂度
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10 , M = 21 , mod = 1e9 + 7;
int f[M][N],fac[N],inv[N];
int q,n,maxn=1e6,m;
bool vis[N];
int fpow(int a,int b){
int res=1;
while(b){
if(b&1) res=(res*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return res;
}
int C(int x,int y){
if(x==y) return 1;
if(x>y||!x||!y) return 0;
return fac[y]*inv[x]%mod*inv[y-x]%mod;
}
int invv(int x){
return fpow(x,mod-2);
}
void solve(){
fac[0]=inv[0]=1;
for(int i=1;i<=maxn;i++){
fac[i]=fac[i-1]*i%mod;
inv[i]=invv(fac[i]);
}
for(int i=1;i<=maxn;i++) f[1][i]=1;
for(int i=1;i<=20;i++){
for(int j=2;j<=maxn;++j){
if(!f[i][j]) continue;
for(int k=2;k*j<=maxn;k++){
f[i+1][k*j]=(f[i+1][k*j]+f[i][j])%mod;
}
}
}
}
signed main(){
solve();
cin>>q;
while(q--){
cin>>m>>n;
if(m==1){
cout<<fpow(2,n-1)<<endl;
continue;
}
int res=0;
for(int i=1;i<=min(n,20ll);i++){
res=(res+f[i][m]*C(i,n))%mod;
//cout<<f[i][m]<<" ";
}
res=(res*fpow(2,n-1)%mod)%mod;
cout<<res<<endl;
}
return 0;
}