Educational Codeforces Round 33 (Rated for Div. 2) E. Counting Arrays [数论II][组合数学]

题目:http://codeforces.com/contest/893/problem/E

 

题意:给出1e5组询问,每组要求y个整数乘积为x,输出组合种类数。(x,y<=1e6)

题解:把x分解成它的所有质因子乘积的形式,例如18=2*3*3 则可以把每个质因子分解为可空的y份,可利用组合数计算。假设有1个数字要分解为3份,可假设为1+3个数字分解为不可空的3份,转化为高中数学的隔板问题,cnt个数字分解为y份答案为$C^{y-1}_{cnt+y-1}$,分解的所有情况的乘积则为答案。先初始化1e6的素数表,分解每个数字,利用快速幂log计算组合数。

但是不能暴力对每一个数字寻找质因数,1e6*1e5肯定会T。需要做一些优化,先初始化出每个数字最小的质因子,然后从x开始向下转移,1e6的数字质因子数不超过20种,复杂度为O(q*20*logx)。

#include<bits/stdc++.h>
#define pii pair<int, int>
#define mod 1000000007
#define mp make_pair
#define pi acos(-1)
#define eps 0.00000001
#define mst(a,i) memset(a,i,sizeof(a))
#define all(n) n.begin(),n.end()
#define lson(x) ((x<<1))
#define rson(x) ((x<<1)|1)
#define inf 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int maxn = 1.5e6 + 500;
vector<int>prime;
int isprime[maxn];
void getprimelist(int t)
{
    mst(isprime, 1);
    isprime[1] = 0;
    for (int i = 2; i <= t; ++i)
    {
        if (isprime[i])prime.push_back(i);
        for (int j = 0; j < prime.size() && prime[j] * i <= t; ++j)
        {
            isprime[prime[j] * i] = 0;
            if (i%prime[j] == 0)break;
        }
    }
}
ll quickmod(ll a, ll b)
{
    ll ans = 1;
    while (b)
    {
        if (b & 1)
            ans = ans*a%mod;
        b >>= 1;
        a = (a%mod)*(a%mod) % mod;
    }
    return ans;
}
ll c[maxn];
ll C(ll n, ll m)
{
    return c[n] * quickmod(c[m] * c[n - m] % mod, mod - 2) % mod;
}
int init[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int i, j, k, m, n;
    getprimelist(1005000);
    c[0] = 1;
    c[1] = 1;
    for(int i=  2;i<=1005555;++i)
        c[i] = c[i - 1] * i%mod;
    int T;
    for(int i = 2;i<=1000000;++i)
    {
        if(isprime[i])
        {
            init[i]=i;
            continue;
        }
        for(auto it :prime)
        {
            if(i%it==0)
            {
                init[i]=it;
                break;
            }
        }
    }
    cin >> T;
    while (T--)
    {
        cin >> n >> m;
        ll ans = 1;
        while(n>=2)
        {
            int cnt = 0;
            int now = init[n];
            while (init[n]==now)
            {
                n /= now; cnt++;
            }
            ll tt = C(cnt + m - 1, m - 1);
            ans = ans*tt%mod;
        }
        ll tt = quickmod(2, m - 1);
        ans = tt*ans%mod;
        cout << ans << endl;
    }
    return 0;
}

 

posted @ 2017-11-28 16:15  Meternal  阅读(187)  评论(0编辑  收藏  举报