629. K个逆序对数组

244 阅读2分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」。

题目

给出两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个逆序对的不同的数组的个数。

逆序对的定义如下:对于数组的第i个和第 j个元素,如果满i < j且 a[i] > a[j],则其为一个逆序对;否则不是。

由于答案可能很大,只需要返回 答案 mod 109 + 7 的值。

示例1

输入: n = 3, k = 0
输出: 1
解释: 
只有数组 [1,2,3] 包含了从1到3的整数并且正好拥有 0 个逆序对。

思路分析

这个n和k,数字有很大,看看能不能找出转移方程,基本就是动态规划。

那么我们肯定假设,n=a,k=b时,我们可以找到所有包含从 1 到 a 的数字,且恰好拥有 b 个逆序对的不同的数组的个数为M。

如果a+1的时候,就相当于在现有的M个数组里增加a+1个位置(这个是高中的数学知识),分别会导致所有包含从 1 到 a+1 的数字,且恰好拥有 (b到b+a) 个逆序对的不同的数组的个数为初始值+1。

如果是考虑找到所有包含从 1 到 a 的数字,且恰好拥有 b+1 个逆序对的不同的数组的个数,这也可以从1到a-1的数字,恰好拥有b-a到b+1个逆序对得到。[这部分算的有点抽象,不过代码肯定是对的]

 int kInversePairs(int n, int k) {
        if (k == 0)return 1;
        int t = 1000000007;
        int dp[n + 1][k + 1];
        for (int i = 0; i < n + 1; i ++){
            for(int j = 0; j < k + 1; j ++){
                if (j == 0)dp[i][j] = 1;
                else dp[i][j] = 0;
            }
        }
        for(int i = 2; i < n + 1; i ++){
            for(int j = 1; j < k + 1 ; j ++){
                int c = dp[i][j];
                for(int k = j; k >= 0 && k >= j - i + 1; k --){
                    c = (c + dp[i - 1][k]) % t;
                }
                dp[i][j] = c;
            }
        }
        return dp[n][k];
    }