1. 程式人生 > >396A On Number of Decompositions into Multipliers (組合數學+思維)

396A On Number of Decompositions into Multipliers (組合數學+思維)

#include<bits/stdc++.h>
using namespace std;
#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define read(x,y) scanf("%d%d",&x,&y)
#define ll long long
#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int  maxn =1e6+5;
const int mod=1e9+7;
ll powmod(ll x,ll y){ll t=1;for(;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod;return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
題目大意:給定n個數位,
其目標是m,要求有多少種分解方式。

組合計數,首先把總目標數字質因分解,
根據唯一分解性定理,
可以知道每次隔板其計數情況不會重複,
假如目標值為p1^k1*p2^k2*p3^k3*...
相當於有m種不同的球,個數為k1,k2,...km,
放入k個框中有多少種不同的放法。
分別對每種球進行k隔板,進行計數,
答案就是C(k+k1-1,k)*...C(k+km-1,k)。
*/
///資料域
ll n,x;
ll ans;
map<ll,int> mp;
map<ll,int>::iterator it;
///篩法篩素數
int prim[maxn],tot=0;
int vis[maxn];
void sieve()
{
    for(int i=2;i<maxn;i++)
    {
        if(vis[i]==0) prim[tot++]=i;
        for(int j=0;j<tot;j++)
        {
            if(1LL*i*prim[j]>=maxn) break;
            int k=i*prim[j];  vis[k]=1;
            if(i%prim[j]==0) break;
        }
    }
}
///組合數階乘逆元
ll fac[maxn],inv[maxn];
void init()
{
    fac[0]=1;for(int i=1;i<maxn;i++) fac[i]=fac[i-1]*i%mod;
    inv[maxn-1]=powmod(fac[maxn-1],mod-2);
    for(int i=maxn-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll n,ll m)
{
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}

int main()
{
    sieve(); init();
    scanf("%lld",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%lld",&x);
        int tx=x,M=0;
        ll ans=1;
        for(int i=0;prim[i]<=tx&&i<tot;i++)
        {
            while(x%prim[i]==0)
            {
                x/=prim[i];
                mp[prim[i]]++;///計數陣列遞增
                M++;
            }
        }
        if(x>1) mp[x]++;
    }
    ans=1;
    for(it=mp.begin();it!=mp.end();it++)
    {
        int tp=it->second;
        ans=ans*C(tp+n-1,tp)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}