D - Factorization
题目大意:给定n,m。求n个数相乘等于m的方案个数
思路:对m进行质因数分解,求出每一个质因数的个数,分别求出每一个质因数有多少种排列方式,求所有质因数排列方式的乘积即可。把每一个质因数都看成一种小球,有n个盒子,假设一个质因数有a个,即a个相同小球放入n个盒子的问题。隔板法:在a-1个空隙中插入n-1个隔板,结果为C(a-1,n-1)。又因为盒子可以为空(用1补),该问题又变为a+n个小球放入n盒子的问题,最终结果为C(a+n-1,n-1)。由于组合数的计算中有插法运算,而且取模数较大,需要逆元。原因:a除以一个数模p,等于a乘这个数的逆元模p。
求逆元:
费马定理:当a和p满足gcd(a,p)=1,且p为质数,则a的p次方和a同余(a^p===a(mod p)),
即a*a^p-2===1(mod p),用快速幂算出a^p-2,即a的逆元
计算阶乘的逆元:inv[i]=inv[i+1]*(i+1)%mod(先把inv[i+1]算出来)||(inv[i]=(inv[i-1]*power(i,mod-2))%mod)。
计算连续的数的逆元:inv[i]=(p-(p/i))*inv[p%i]%mod。
const ll mod = 1e9 + 7;
ll f[300005];
ll inv[300005];
ll power(ll a, ll b) { //快速幂算出a的逆元
ll ans = 1;
while (b) {
if (b & 1)
ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void init() { //初始化把阶乘和阶乘的逆元算出
inv[0] = inv[1] = f[0] = f[1] = 1;
for (int i = 2; i <= 3e5+5; i++) {
f[i] = (i * f[i - 1]) % mod;
inv[i] = (inv[i - 1] * power(i, mod - 2)) % mod;
}
}
ll C(int a,int b) { //计算C(a,b)
return (f[a] * inv[b] % mod * inv[a - b] % mod) % mod;
}
void solve() {
int n, m;
cin >> n >> m;
init();
ll ans = 1;
for (int i = 2; i <= m; i++) {
if (m % i == 0) { //唯一分解
int cnt = 0;
while (m % i == 0) {
cnt++;
m /= i;
}
ans = ans * C(cnt + n - 1, n - 1) % mod;
}
}
cout << ans << '\n';
}
要搞课设,复习,今天又要掉分。。。。。