LeetCode 629 K个逆序对数组
题目链接:https://leetcode-cn.com/problems/k-inverse-pairs-array/
题目大意
略。
分析
首先,1~n 这 n 个数所能产生的最大逆序对为 n * (n - 1) / 2 对。
设 dp[i][j] 表示 1~i 能产生 j 对逆序对的排列种数。
这里定义一下如果下标为负数,这一项为 0。
在考虑接下来一个事实:对于序列 1,2,3,4,5 和 2,5,7,9,10,在这个问题下,我可以说这两个序列是等价的,因为产生逆序对的本质是大小关系而不是数实际的大小。
现在考虑状态转移方程。
首先当 j > i * (i - 1) / 2 时,dp[i][j] = 0。
其次当 j = 0 时,dp[i][0] = 1,只有顺着排一种方法。
以上确定了初始状态。
对于其他 dp[i][j],我们如果考虑在队头放第 k 大的数,那么这个数就贡献了 k - 1 对逆序对,剩下的 i - 1 个不同的数就可以转化为子问题,也就是 dp[i - 1][j - k]。
同理我们也可以在队头放其他数,分别求一下贡献,就能得到状态转移方程:$$dp[i][j] = \sum_{k = max(0, j - i + 1)}^{j} dp[i - 1][k]$$
仔细观察前后两项的关系可以发现:$$dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][max(0, j - i + 1) - 1]$$
不过不推这个式子也能做,搞个前缀和即可。
代码如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 int dp[2][1007], mod = 1e9 + 7, now = 0; 3 public: 4 int kInversePairs(int n, int k) { 5 dp[now][0] = 1; 6 7 for(int i = 1; i <= n; ++i) { 8 now = !now; 9 dp[now][0] = 1; 10 for(int j = 1; j <= k; ++j) { 11 if(2 * j > i * (i - 1)) break; 12 dp[now][j] = (dp[now][j - 1] + dp[!now][j]) % mod; 13 if(j - i >= 0) dp[now][j] = (dp[now][j] - dp[!now][j - i] + mod) % mod; 14 } 15 } 16 17 return dp[now][k]; 18 } 19 };