题目传送门
题意:
一个正整数x,把x分解为y个整数,有多少种方案。
相同的数字,顺序不同,认为方案不同。
数据范围:
。题解:
由唯一分解定理知:
。其中 是质数。把x分解成y个整数等价于把每种质因子
分成y组,允许空组出现。假设答案是
,那么每种质因子对答案的贡献是 。解释
:把 个质数分成 组,允许空组,那就相当于 个质数分为 组 ,不允许空组,因为你可以把每组减去1,那就出现了空组,所以是等价的。用隔板法得出该式。由于负数的存在,并且x是正整数,所以y个数中有偶数个负数,最后
。计算组合数时预处理出阶乘逆元会更快。每次都计算所需阶乘逆元是比较慢的。
感受:
学会了隔板法。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 105 ;
const int maxm = 1005 ;
const ll mod = 1e9 + 7 ;
ll fac[2000005] ;
ll inv[2000005] ;
ll qpow(ll a , ll b)
{
ll ans = 1 ;
while(b)
{
if(b & 1) ans = (ans * a) % mod ;
b >>= 1 , a = (a * a) % mod ;
}
return ans % mod ;
}
void init()
{
fac[0] = fac[1] = 1 ;
for(int i = 2 ; i <= 2e6 ; i ++)
fac[i] = (fac[i - 1] * i) % mod ;
inv[2000000] = qpow(fac[2000000] , mod - 2) ;
for(int i = 1999999 ; i >= 0 ; i --)
inv[i] = inv[i + 1] * (i + 1) % mod ;
}
int cnt = 0 ;
bool vis[maxm] ;
int prime[maxm] ;
void get_prime()
{
memset(vis , 0 , sizeof(vis)) ;
vis[1] = 1 ;
for(int i = 2 ; i <= maxm - 5 ; i ++)
{
if(!vis[i])
prime[++ cnt] = i ;
for(int j = 1 ; j <= cnt && i * prime[j] <= maxm - 5 ; j ++)
{
vis[i * prime[j]] = 1 ;
if(i % prime[j] == 0) break ;
}
}
}
int num = 0 ;
int p[maxn] , c[maxn] ;
void init(int x)
{
num = 0 ;
for(int i = 1 ; i <= cnt && prime[i] * prime[i] <= x ; i ++)
{
if(x % prime[i] == 0)
{
p[++ num] = prime[i] , c[num] = 0 ;
while(x % prime[i] == 0)
{
c[num] ++ ;
x /= prime[i] ;
}
}
}
if(x > 1) p[++ num] = x , c[num] = 1 ;
}
ll C(int n , int m)
{
return fac[n] * inv[m] % mod * inv[n - m] % mod ;
}
int main()
{
int q ;
scanf("%d" , &q) ;
get_prime() ;
init() ;
while(q --)
{
int x , y ;
ll ans = 1ll ;
scanf("%d%d" , &x , &y) ;
init(x) ;
for(int i = 1 ; i <= num ; i ++)
ans *= C(c[i] + y - 1 , y - 1) , ans %= mod ;
ans *= qpow(2 , y - 1) , ans %= mod ;
printf("%lld\n" ,ans) ;
}
return 0 ;
}
来源:CSDN
作者:敲代码的欧文
链接:https://blog.csdn.net/Irving0323/article/details/104145482