zoukankan      html  css  js  c++  java
  • 【洛谷T96628】统计

    Description

    给定$n$, $m$,求十进制$n$位数每个位数之积等于k的方案数

    Solution

    dp+高精+数学

    考虑$k=0$的情况,由于可以有若干个$0$,所以方案数为$sumlimits_{i=1}^{n}{nchoose m} imes 9^{n-i}$

    考虑另外的情况,我们将$k$分解质因数,如果$k$还有除了$2$,$3$,$5$,$7$之外的质因数那么方案数为$0$

    其余的情况我们考虑一个$dp$,定义$f[i][j][k][l][o]$表示考虑前$i$位,前$i$位之积$=2^j imes 3^k imes 5^l imes7^o$的方案数是多少,显然第一维可以用滚动数组压掉,转移就类似于背包的转移即可。

    由于本题十分恶心的没有取模,所以我们需要高精度计算

    Code

    #include <bits/stdc++.h>
    // check if it is judged online
    #define LOCAL
    namespace shl {
        const int mod = 10;
        int n, k;
        typedef unsigned long long ull;
        ull C[55][55];
        ull ans[60];
        ull sum[60]; 
        int lens = 1, lena = 1;
        using std::max;
        int f[32][32][32][32][50];
        void add() {
            lena = max(lena, lens);
            for (register int i = 1; i <= lena; ++i)
                ans[i] += sum[i];
            for (register int i = 1; i <= lena; ++i)
                ans[i + 1] += ans[i] / mod, ans[i] %= mod;
            while (ans[lena + 1]) lena++;
        }
        void mul(ull x, ull base, int mi) {
            memset(sum, 0, sizeof(sum));
            lens = 1;
            sum[1] = 1;
            for (register int i = 1; i <= mi; ++i) {
                for (register int j = 1; j <= lens; ++j) sum[j] *= base;
                for (register int j = 1; j <= lens; ++j)
                    sum[j + 1] += sum[j] / mod, sum[j] %= mod;
                while (sum[lens + 1]) lens++;            
            }
            for (register int i = 1; i <= lens; ++i) sum[i] *= x;
            for (register int i = 1; i <= lens; ++i)
                sum[i + 1] += sum[i] / mod, sum[i] %= mod;
            while (sum[lens + 1]) lens++;
        }
        void plus(int x[60], int y[60]) {
            int c[100], len = 1;
            memset(c, 0, sizeof(c));
            len = max(x[0], y[0]);
            for (register int i = 1; i <= len; ++i)
                c[i] = x[i] + y[i];
            for (register int i = 1; i <= len; ++i)
                c[i + 1] += c[i] / mod, c[i] %= mod;
            while (c[len + 1]) len++;
            x[0] = len;
            for (register int i = 1; i <= len; ++i)
                x[i] = c[i];
        }
        int main() {
            scanf("%d%d", &n, &k);
            if (k == 0) {
                for (register int i = 0; i <= n; ++i)
                    C[i][0] = C[i][i] = 1;
                for (register int i = 1; i <= n; ++i)
                    for (register int j = 1; j < i; ++j)
                        C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
                for (register int i = 1; i <= n; ++i) {
                    mul(C[n][i], 9ll, n - i);
                    add();
                }
                for (register int i = lena; i >= 1; --i)
                    printf("%d", ans[i]);
                puts("");
                return 0;
            }
            int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
            while (k % 2 == 0) a1++, k /= 2;
            while (k % 3 == 0) a2++, k /= 3;
            while (k % 5 == 0) a3++, k /= 5;
            while (k % 7 == 0) a4++, k /= 7;
            if (k > 1) {
                puts("0");
                return 0;
            }
            f[0][0][0][0][0] = 1;
            f[0][0][0][0][1] = 1;
            for (register int i = 1; i <= n; ++i) {
                for (register int j = a1; j >= 0; --j)
                    for (register int k = a2; k >= 0; --k)
                        for (register int l = a3; l >= 0; --l)
                            for (register int o = a4; o >= 0; --o) {
                                if (j >= 1) plus(f[j][k][l][o], f[j - 1][k][l][o]); //2
                                if (k >= 1) plus(f[j][k][l][o], f[j][k - 1][l][o]); //3
                                   if (j >= 2) plus(f[j][k][l][o], f[j - 2][k][l][o]); //4
                                    if (l >= 1) plus(f[j][k][l][o], f[j][k][l - 1][o]); //5
                                    if (j >= 1 && k >= 1) plus(f[j][k][l][o], f[j - 1][k - 1][l][o]); //6
                                if (o >= 1) plus(f[j][k][l][o], f[j][k][l][o - 1]); //7
                                if (j >= 3) plus(f[j][k][l][o], f[j - 3][k][l][o]); //8
                                if (k >= 2) plus(f[j][k][l][o], f[j][k - 2][l][o]); //9
                            }
            }
            for (register int i = max(f[a1][a2][a3][a4][0], 1); i >= 1; --i)
                printf("%d", f[a1][a2][a3][a4][i]);
            return 0;
        }
    }
    int main() {
    #ifdef LOCAL
        freopen("count.in", "r", stdin);
        freopen("count.out", "w", stdout);
    #endif
        shl::main();
        return 0;
    }
  • 相关阅读:
    找数字(递归,二分查找)
    P1759 通天之潜水(不详细,勿看)(动态规划递推,组合背包,洛谷)
    第五讲 二维费用的背包问题(粗糙,勿点)
    VIM基础操作方法汇总
    P2347 砝码称重(动态规划递推,背包,洛谷)
    第三讲 多重背包问题(对背包九讲的学习)
    第二讲 完全背包问题(对背包九讲的学习)
    python 日期、时间、字符串相互转换
    Resource注解无法导入依赖使用javax.annotation的注解类
    Spring的配置文件找不到元素 'beans' 的声明
  • 原文地址:https://www.cnblogs.com/shl-blog/p/11437788.html
Copyright © 2011-2022 走看看