CodeForces 893E (详细思路)

感谢这位大佬的思路

https://blog.csdn.net/xiaolonggezte/article/details/78659058

题意:给定一个正数n,在给定k,要把n分解成k个数的乘积,问有多少种解决方案,顺序不同也不一样哦。

思路:首先要把n分解成k个数的乘积,首先想到的就是质因子,因为质因子不可再分,是为最简,然后我们再把所有的质因子分成k份,这样就解决了问题。

那么问题就可以通过求取把每个质因子分成k份的方法数的乘积,在乘2^(y-1),为什么要乘他,因为题目中要求可以为负,那么我们便只能选取偶数个负数来实现。也就是c(0,y)+c(2,y)+c(4,y)....也就是2^(y-1),下面是转载上面链接的大佬的代码,不过加了每一步自己的理解~还有对挡板法的理解!~

 

https://blog.csdn.net/qq_39942341/article/details/80246780

还有这位大佬的挡板法讲的很好,学到了!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=2e6+10;
const ll md=1e9+7;
ll fac[maxn];
void Init(){
    fac[0]=1;
    for(int i=1;i<maxn;i++) fac[i]=fac[i-1]*i%md;
}
ll pows(ll x,ll n){
    ll ret=1;
    while(n){
        if(n&1) ret=ret*x%md;
        x=x*x%md;
        n>>=1;
    }
    return ret;
}
ll c(int n,int m){
    if(m==0||n==m) return 1;
    if(m*2>n) m=n-m;
    return fac[n]*pows(fac[n-m],md-2)%md*pows(fac[m],md-2)%md;
}
int main(){
    Init();
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        ll ans=pows(2,m-1);   /*题目表示分解后的数可以为负,要求乘积为n,那么我们只能选取偶数个数让其为负,这样不会影响最终结果
                                那么就可以表示为c(y,0)+c(y,2)+c(y,4)等等,前面的等式就等于2^(y-1)*/
        for(int i=2;i*i<=n;i++){  /*分解质因子*/
            if(n%i==0){
                int cnt=0;
                while(n%i==0){ /*统计单个质因子个数*/
                    cnt++;
                    n/=i;
                }
                ans=ans*c(m+cnt-1,cnt)%md;  /*把每个k个质因子分解成m份,再把另一个质因子分解成m份, 依次处理
                那么在正数情况下,其可能总数就是每种可能的乘积,因为都是质因子,所以不会重复(空的补1)*/
            }  /*至于最关键的地方,把k分成y份(可以为空),为什么是C(Y-1,K+Y-1)呢?
                 首先要知道我们把n个物体分成m份,不可以为空,那么可能情况就是C(m-1,n-1)(从n个物体之间的n-1个
                 空中选取m-1(分成m份要m-1个板子)个放入挡板,这样就分成了m份),然后我们类比想像n+m个物体分成
                 m份那就是c(m-1,n+m-1),这是不允许为空的状态,但是题目要求可以为空,我们怎么办?我们可以把这m份
                 物体每个都减少1,这样我们还是把他分成了m份,但是里面出了空的情况,而剩余的总数为(n+m)-m==n
                 也就是我们的n个质因子,然后就会发现我们把n个质因子分成了m份,并且包含了空的情况,对不对?
                 这就是C(Y-1,K+Y-1),转换思想~~谢谢zk,sz,lf的讲解,懂了懂了~~~*/
        }
//        cout<<ans<<" "<<n<<endl;
        if(n>1) ans=ans*m%md;  /*如果n为1只有一种情况,那就是n本身是个质数,对于分解质因子,对其没有作用*/
        printf("%lld\n",ans);
    }
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值