给定数字的排列和组合

时间:2014-09-27 05:54:04

标签: c++ algorithm

I want to count the number of combinations we can prouduce of a given number.

例如M =数字位数,N = 4数字长度

M= 3 ({3,7,5}) and N=4
Possible combinations:(The given 3 numbers must be there in the combination)
3577, 3557, 7353 and 5735 and other (32  possible combination)

我在网上找到了这个代码。这段代码给了我正确的输出,但我无法理解它正在使用什么逻辑。

请解释下面的代码及其时间复杂程度。

提前致谢。

#define LL long long int
#define sd(x) scanf("%d", &x)
#define MOD 1000000007
#define D double
#define LD long double

#define N 200

LL dp[N][N];

inline void solve(){
    int n, m, i, j;
    sd(m); sd(n);
    memset(dp, 0, sizeof dp);
    dp[1][1] = m;
    for(i = 1; i < n; i++){
        for(j = 1; j <= i && j <= m; j++){
            (dp[i + 1][j] += j * dp[i][j]) %= MOD;
            (dp[i + 1][j + 1] += (m - j) * dp[i][j]) %= MOD;
        }
    }
    cout<<dp[n][m]<<endl;
}

1 个答案:

答案 0 :(得分:1)

代码中的dp代表dynamic programming。在许多编程竞赛平台中,它都是state

问题出在此处:

dp[i][j]表示在j中使用M个不同数字形成长度为i的数字的方式。一些要求:j <= ij <= M

所以我们假设,我们已经知道dp[i][j]

然后我们可以简单地计算dp[i + 1][j] = j * dp[i][j](再多一个插槽)。

对于dp[i + 1][j + 1],这意味着我们可以在插槽中插入一个插槽 M-j 选项。所以dp[i + 1][j + 1] = (M - j) * dp[i][j]

为什么M - j?回想一下

  j

中的

M 不同的数字

最后,通过这两个转换公式和dp[1][1],我们可以计算dp[i][j]i <= N中的任何j <= M and j <= i

更新:示例

N = 4M = 3

我们首先计算dp[1][1],显然是dp[1][1] = 3。只有一个广告位,我们有M个选项。 (回忆dp)的定义

然后我们进入循环:从dp[1][1]开始:

计算dp[1 + 1][1]:这意味着我们有两个插槽和一个数字。我们这里只有一个选择 - 再次使用相同的数字。所以dp[1 + 1][1] = 1 * dp[1][1] = 3。在您的示例中,dp[2][1]代表{3, 3} {5, 5} {7, 7};

要计算dp[1 + 1][1 + 1]:这意味着我们有两个广告位和两个不同的数字,因此我们有M - 1个选项。所以它等于dp[2][2] = 2 * dp[1][1] = 6。在您的示例中,dp[2][2] represents {3, 5}, {3, 7}, {5, 3}, {5, 7}, {7, 3}, {7, 5}

然后按照循环,我们将转到dp[4][3],这就是答案。