629. K Inverse Pairs【Hard】 动态规划
2017-09-21 16:28
99 查看
作死试了一个看起来比较简单的HARD题,刚开始看到题目还觉得有点思路,然而后来却发现没法降低时间复杂度。
我的思路如下:每次知道了第n个状态下所有k的情况(即知道所有a[1,2..n][k]),则n+1的情况便可求出来。
因为从n到n+1是相当于在原来的1,2..n的无序序列中加入n+1这个数,那么这个数,n+1,可以放置的位置有n+1位,
例如n=4时,n+1=5,加入5的情况有
xxxx5 k+=0
xxx5x k+=1
xx5xx k+=2
x5xxx k+=3
5xxxx k+=4
<n,k>下有a
[k]个序列,那么就相当于给<n+1, k+i> (i=0,1,2,3,4)都贡献了a
[k]个序列
相当于给a[n+1][k] , a[n+1][k+1] , a[n+1][k+2] , a[n+1][k+3] , a[n+1][k+4]都加上了a
[k]
所以循环n次之后就能知道a
[k]的值了
看了网上的博客才知道这题可以用类似求等比数列的办法来算每个<n,k>的值,降低了复杂度,优化了算法。
原因是:由前面的推导,可以知道:
a
[k] = a[n - 1][k] + a[n - 1][k - 1] + ... + a[n - 1][k - n + 1]
用k-1替换k,就能得到:
a
[k - 1] = a[n - 1][k - 1] + a[n - 1][k - 2] + ... + a[n - 1][k - n]
一式减去二式,得到:
a
[k] = a
[k - 1] + a[n - 1][k] - a[n - 1][k - n]
当k>=n的时候,a[n - 1][k - n]才会有意义,所以要判断一下k和n的关系,如果k>=n的话,就要减去最后一项
这个递推式减少了一个循环,使算法更高效,代码如下:
我的思路如下:每次知道了第n个状态下所有k的情况(即知道所有a[1,2..n][k]),则n+1的情况便可求出来。
因为从n到n+1是相当于在原来的1,2..n的无序序列中加入n+1这个数,那么这个数,n+1,可以放置的位置有n+1位,
例如n=4时,n+1=5,加入5的情况有
xxxx5 k+=0
xxx5x k+=1
xx5xx k+=2
x5xxx k+=3
5xxxx k+=4
<n,k>下有a
[k]个序列,那么就相当于给<n+1, k+i> (i=0,1,2,3,4)都贡献了a
[k]个序列
相当于给a[n+1][k] , a[n+1][k+1] , a[n+1][k+2] , a[n+1][k+3] , a[n+1][k+4]都加上了a
[k]
所以循环n次之后就能知道a
[k]的值了
#include <iostream> using namespace std; const int md = 1000000007; int a[1001][1001] = {{0}}, n, j, i, x, k; int main() { cin >> n >> k; for (i = 1; i <= n; ++i) { if (i == 1) a[i][0] = 1; else for (j = 0; a[i - 1][j] > 0 && j <= k; ++j) for (x = 0; x < i && j + x <= k; ++x) { a[i][j + x] += a[i - 1][j]; a[i][j + x] %= md; } } cout << a [k]; return 0; }
看了网上的博客才知道这题可以用类似求等比数列的办法来算每个<n,k>的值,降低了复杂度,优化了算法。
原因是:由前面的推导,可以知道:
a
[k] = a[n - 1][k] + a[n - 1][k - 1] + ... + a[n - 1][k - n + 1]
用k-1替换k,就能得到:
a
[k - 1] = a[n - 1][k - 1] + a[n - 1][k - 2] + ... + a[n - 1][k - n]
一式减去二式,得到:
a
[k] = a
[k - 1] + a[n - 1][k] - a[n - 1][k - n]
当k>=n的时候,a[n - 1][k - n]才会有意义,所以要判断一下k和n的关系,如果k>=n的话,就要减去最后一项
这个递推式减少了一个循环,使算法更高效,代码如下:
class Solution { public: int kInversePairs(int n, int k) { const int md = 1000000007; int a[1001][1001] = {{0}}; int j, i; a[0][0] = 1; for (i = 1; i <= n; ++i) { a[i][0] = 1; for (j = 1; j <= k; ++j) { a[i][j] = (a[i - 1][j] + a[i][j - 1]) % md; if (j >= i) { a[i][j] = (a[i][j] - a[i - 1][j - i] + md) % md; } } } return a [k]; } };
相关文章推荐
- AtCoder Regular Contest 066 E - Addition and Subtraction Hard 动态规划
- 87. Scramble String *HARD* 动态规划
- 514. Freedom Trail 【Hard】 动态规划
- 312. Burst Balloons 难度:hard 类别:分治、动态规划
- 115.leetcode Distinct Subsequences(hard)[动态规划]
- 689. Maximum Sum of 3 Non-Overlapping Subarrays 【Hard】 动态规划
- vijos1059【动态规划】
- HDU 2059-龟兔赛跑(动态规划)
- [hard]146. LRU Cache
- 动态规划求解最长公共子序列与最长公共子串
- 【动态规划】公路乘车 tyvj1015
- CSU 1325 A very hard problem (莫比乌斯反演+分块求和优化)
- HDU 2577:How to Type(动态规划或模拟)
- hard negative mining分析得最好的理解
- 动态规划-最长公共子序列
- noip2001 数的划分 (动态规划)
- 动态规划(Memory and Scores,cf 712D)
- Piggy-Bank HDU - 1114 动态规划
- git reset --hard HEAD^与git reset --hard HEAD的区别
- BZOJ2302: [HAOI2011]Problem c|动态规划|组合数学