给定数字的排列和组合

Permutation and Combination of a given numbers

本文关键字:组合 排列 数字      更新时间:2023-10-16
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;
}

代码中的dp表示dynamic programming。在许多编程竞赛平台中,它从state站出来。

问题在这里:

dp[i][j]表示在M中使用j不同数字来形成长度为 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],我们可以计算出i <= Nj <= M and j <= i的任何dp[i][j]

更新:示例

N = 4M = 3

我们从计算dp[1][1]开始,这显然是dp[1][1] = 3。只有一个插槽,我们M选择。(回想dp的定义(

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

计算dp[1 + 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],这就是答案。