• C. On Number of Decompositions into Multipliers 组合数学


    http://codeforces.com/contest/397/problem/C

    给出n个数字,m = a[1] * a[2] * a[3] ... * a[n]

    要求把m分成n个不一样的乘积,求方案数。

    就是35分成2分的话,1 * 35 。35 * 1。5 * 7。7 * 5

    首先数字很大,表示出来是不可能的。

    考虑储存它的质因数,例如12。 12 = 2 * 2 * 3

    如果要分成4分的话,首先对每一种质因数放。

    例如2,有2个,可以表示为(4份)

    2 * 2 * 1 * 1

    2 * 1 * 2 * 1

    ......

    4 * 1 * 1 * 1

    ..........

    这是一个经典的组合数学问题,n个球,放在m个箱子,可以空,可以重叠。一共有C(n + m - 1, m - 1)种。

    这里空的用了1来表示。

    然后不对呀,这不是12的分解情况,它还有一个质因子嘛,3.

    分成

    3 * 1 * 1 * 1

    1 * 3 * 1 * 1

    1 * 1 * 3 * 1

    1 * 1 * 1 * 3

    ,然后种数相乘,就是答案,为什么呢?比如(2 * 2 * 1 * 1) X (3 * 1 * 1 * 1) = (6 * 2 * 1 * 1),是一种情况。

    因为有500个数字,如果每个数字都是2^30次方,一共有15000个2,但是格子最多500个。

    可以预处理组合数C[15000][500]即可,不会爆内存,

    一开始一直re,是我自己没分析好。、

    最后也没预处理,因为没想到用C[15000][500]这样, 用的是逆元。我太水了太渣了

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    #define MY "H:/CodeBlocks/project/CompareTwoFile/DataMy.txt", "w", stdout
    #define ANS "H:/CodeBlocks/project/CompareTwoFile/DataAns.txt", "w", stdout
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    map<int, int>mp;
    const int MOD = 1e9 + 7;
    LL quick_pow(LL a, LL b, LL MOD) {  //求解 a^b%MOD的值
        LL base = a % MOD;
        LL ans = 1; //相乘,所以这里是1
        while (b) {
            if (b & 1) {
                ans = (ans * base) % MOD; //如果这里是很大的数据,就要用quick_mul
            }
            base = (base * base) % MOD;    //notice。注意这里,每次的base是自己base倍
            b >>= 1;
        }
        return ans;
    }
    LL C(LL n, LL m, LL MOD) {
        if (n < m) return 0; //防止sb地在循环,在lucas的时候
        if (n == m) return 1;
        LL ans1 = 1;
        LL ans2 = 1;
        LL mx = max(n - m, m); //这个也是必要的。能约就约最大的那个
        LL mi = n - mx;
        for (int i = 1; i <= mi; ++i) {
            ans1 = ans1 * (mx + i) %MOD;
            ans2 = ans2 * i % MOD;
        }
        return (ans1 * quick_pow(ans2, MOD - 2, MOD) % MOD); //这里放到最后进行,不然会很慢
    }
    
    void work() {
        mp.clear();
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            int x;
            scanf("%d", &x);
            int end = (int)sqrt(x + 0.5);
            for (int j = 2;  j <= end; ++j) {
                if (x % j == 0) {
                    mp[j]++;
                    x /= j;
                    while (x % j == 0) {
                        mp[j]++;
                        x /= j;
                    }
                    end = (int)sqrt(x + 0.5);
                }
            }
            if (x != 1) mp[x]++;
        }
        LL ans = 1;
        for (map<int, int> :: iterator it = mp.begin(); it != mp.end(); ++it) {
    //        cout << it->first << " " << it->second << endl;
            int val = it->second;
    //        if (val > maxn) while(1);
    //        ans *= C[val + n - 1][n - 1];
            ans *= C(val + n - 1, n - 1, MOD);
            ans %= MOD;
        }
        printf("%I64d
    ", ans);
    }
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    站立会议第二天
    站立会议第一天
    Scrum_Sprint
    电梯演讲之加减乘除
    The group WHATEVER is formed today
    awk简介(使用方法)
    关于Java进程流程简介
    Bootstrap_导航
    Bootstrap_按钮工具栏
    Bootstrap_下拉菜单
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6106464.html
Copyright © 2020-2023  润新知