给定两个整数n和k,我想计算有多少个不同的数组由1到n的数字组成,这样就有正好k个逆对。 (即,对i,j使i<j
和a[i]>a[j]
)Mod 10 ^ 9 + 7。
我正在使用动态编程,我将DP[i][j]
定义为具有i个元素且具有正好j反转的数组的数量,然后我导出了重复:
DP[i][j]=DP[i-1][j]+dp[i-1][j-1]+...+dp[i-1][j-i+1]
另外,我注意到了:
DP[i][j-1]=DP[i-1][j-1]+DP[i-1][j-2]+...+DP[i-1][j-i]
因此,结合两个总和,我们得到:
DP[i][j]=DP[i-1][j]+DP[i][j-1]-DP[i-1][j-i]
我编写了以下动态编程解决方案,该解决方案适用于大n直到n,k大约为800.但是,一旦我传递了这些值(例如,n = 1000,k = 990),结果就会溢出而我不是确定为什么会这样。这是我的解决方案:
class Solution {
public:
long long MOD = 1e9+7;
int kInversePairs(int n, int k) {
vector< vector<long long> > dp(1001, vector<long long>(1001, -1));
return solve(dp, n, k);
}
long long solve(vector< vector<long long> >& dp, int n, int k){
if (k<0)return 0;
if (k==0)return 1;
if (n==0)return 0;
if (dp[n][k]!=-1)return dp[n][k];
dp[n][k]=solve(dp, n-1, k)%MOD;
dp[n][k]+=solve(dp, n, k-1)%MOD;
dp[n][k]-=solve(dp, n-1, k-n)%MOD;
//if (dp[n][k]<0){
// cout << "Overflow: " << solve(dp, n-1, k-n) << " " << solve(dp, n-1, k) << " " << solve(dp, n, k-1) << endl;
//}
return dp[n][k]%=MOD;
}
};
答案 0 :(得分:2)
我最终想出了答案。我在这里添加完成。
在dp[n][k]-=solve(dp, n-1, k-n)%MOD;
行之后,有可能dp [n] [k]小于零,因为我们每时每刻都采用模MOD,所以即使dp [n]的实际值[ k]在此行之前是1e20,我们采用模MOD,因此其值可能会降至零。所以在这一行之后,该值可能是负数。
我解决这个问题的方法是在取最后一个模之前添加+ MOD。这是工作代码:
class Solution {
public:
long long MOD = 1e9+7;
int kInversePairs(int n, int k) {
vector< vector<long long> > dp(1001, vector<long long>(1001, -1));
return solve(dp, n, k);
}
long long solve(vector< vector<long long> >& dp, int n, int k){
if (k<0)return 0;
if (k==0)return 1;
if (n==0)return 0;
if (dp[n][k]!=-1)return dp[n][k];
dp[n][k]=solve(dp, n-1, k)%MOD;
dp[n][k]+=solve(dp, n, k-1)%MOD;
dp[n][k]-=solve(dp, n-1, k-n)%MOD;
dp[n][k]+=MOD; //just in case it became negative
return dp[n][k]%=MOD;
}
};