WHU 1568 Product (DP、逆元)

题意:

      定义f(x) 为数x的所有数字的乘积.

      求满足f(k)=f(x)的不同的不含数字1的k的个数.

      x的长度小于50.

      不超过1000组数据.


Solution:

      由于函数是乘积的形式,可以由质因子着手分析:

      数字的范围是1~9,1~9中只有2,3,5,7 四个质数,即f(x)可以表示为这四个质数的幂的乘积的形式.

      注意到x的长度小于50,那么质因子最多不超过150(50个8),这个时候似乎可以通过枚举4 6 8 9这四个因子的个数来,得到答案.因为5,7可以单独处理,2和3的个数可以通过4,6,8,9的个数求得.另外4的个数不超过75.而6,8,9的个数也不超过50.从时间复杂度上看是我们能够接受的.但是数据有1000组.这似乎迫使我们采用能够预处理一些我们需要的东西的算法.

     令f[k][i][j],为长度为k,含有i个2因子,j个3因子的数的个数.

     对于f[k+1],不过是在k的后面加了2~9这8个数,只要对每个数,更新对应的i,j就行了.

     这样我们可以先预处理足够大多的f[k][i][j],因为最多不过150个2因子,100个3因子,所以预处理到f[150][150][100]就够了.

     对于一组输入,统计2,3,5,7这四个因子的个数,利用多重排列的公式计算出答案,因为要对除法取模,所以要用到逆元.

#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
const int MOD = 1000000007;
int n, m;
LL dp[160][160][160], f[200];
int sum[5];
char s[100];
LL Quikpower (LL  Base, LL  Power) {
    LL  k = 1;
    while ( Power > 0) {
        if (Power & 1) k = (k * Base) % MOD;
        Base = (Base * Base) % MOD;
        Power >>= 1;
    }
    return k;
}
LL cnt (LL k, int m, int a, int b) {
    LL ans = k;
    for (int i = 1; i <= a + b; i++)
        ans = ans * (m + i) % MOD;
    ans = ans * Quikpower (f[a], MOD - 2) % MOD;
    ans = ans * Quikpower (f[b], MOD - 2) % MOD;
    return ans;
}
int main() {
    f[0] = 1;
    for (int i = 1; i <= 150; i++)
        f[i] = (f[i - 1] * i) % MOD;
    dp[0][0][0] = 1;
    for (int i = 0; i <= 150; i++)
        for (int s2 = 0; s2 <= 150; s2++)
            for (int s3 = 0; s3 <= 150; s3++) {
                if (dp[i][s2][s3] == 0) continue;
                dp[i + 1][s2 + 1][s3] = (dp[i + 1][s2 + 1][s3] + dp[i][s2][s3]) % MOD;//2
                dp[i + 1][s2][s3 + 1] = (dp[i + 1][s2][s3 + 1] + dp[i][s2][s3]) % MOD; //3
                dp[i + 1][s2 + 2][s3] = (dp[i + 1][s2 + 2][s3] + dp[i][s2][s3]) % MOD;//4
                dp[i + 1][s2 + 1][s3 + 1] = (dp[i + 1][s2 + 1][s3 + 1] + dp[i][s2][s3]) % MOD; //6
                dp[i + 1][s2 + 3][s3] = (dp[i + 1][s2 + 3][s3] + dp[i][s2][s3]) % MOD;//8
                dp[i + 1][s2][s3 + 2] = (dp[i + 1][s2][s3 + 2] + dp[i][s2][s3]) % MOD; //9
            }
    while (scanf ("%d", &n) != EOF) {
        scanf ("%s", s);
        memset (sum, 0, sizeof sum);
        for (int i = 0; i < n; i++) {
            int k = s[i] - '0';
            if (k == 2 || k == 6 || k == 8) sum[0]++;
            if (k == 4 || k == 8) sum[0] += 2;
            if (k == 3 || k == 6) sum[1]++;
            if (k == 9) sum[1] += 2;
            if (k == 5) sum[2]++;
            if (k == 7) sum[3]++;
        }
        int m = sum[0] + sum[1];
        LL ans = 0;
        if (m + sum[2] + sum[3] != 0)
            for (int i = 0; i <= m; i++)
                if (dp[i][sum[0]][sum[1]])
                    ans = (ans + cnt (dp[i][sum[0]][sum[1]], i, sum[2], sum[3]) ) % MOD;
        cout << ans << endl;
    }
}
View Code
原文地址:https://www.cnblogs.com/keam37/p/4448477.html