码迷,mamicode.com
首页 > 编程语言 > 详细

LeetCode 629. K个逆序对数组

时间:2019-07-14 14:58:08      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:event   大小   leetcode   题目   inverse   return   下标   closed   http   

题目链接: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]$$
  不过不推这个式子也能做,搞个前缀和即可。

代码如下

技术图片
 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 };
View Code

 

LeetCode 629. K个逆序对数组

标签:event   大小   leetcode   题目   inverse   return   下标   closed   http   

原文地址:https://www.cnblogs.com/zaq19970105/p/11183886.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!