作死试了一个看起来比较简单的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[n][k]个序列,那么就相当于给<n+1, k+i> (i=0,1,2,3,4)都贡献了a[n][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[n][k]
所以循环n次之后就能知道a[n][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[n][k];
return 0;
}
看了网上的博客才知道这题可以用类似求等比数列的办法来算每个<n,k>的值,降低了复杂度,优化了算法。
原因是:由前面的推导,可以知道:
a[n][k] = a[n - 1][k] + a[n - 1][k - 1] + ... + a[n - 1][k - n + 1]
用k-1替换k,就能得到:
a[n][k - 1] = a[n - 1][k - 1] + a[n - 1][k - 2] + ... + a[n - 1][k - n]
一式减去二式,得到:
a[n][k] = a[n][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[n][k];
}
};