【问题标题】:C++ Overflow when counting the number of K Inverse Pairs计算 K 逆对数时的 C++ 溢出
【发布时间】:2017-08-05 07:45:44
【问题描述】:

给定两个整数 n 和 k,我想计算有多少个不同的数组由从 1 到 n 的数字组成,这样正好有 k 个逆对。 (即配对 i,j 使得 i<ja[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;
    }
};

【问题讨论】:

  • 投反对票的人能否解释他投反对票的原因?我显然已经尝试了很多,我的问题很清楚,而且我没有要求任何人解决我的作业(这不是)。看来我这些天在堆栈溢出上发布的任何问题都毫无理由地被否决了!
  • int kInversePairs, long long solve -- 看到这个问题了吗?当您从 kInversePairs 返回 solve 的结果时,您的编译器应该会警告您。
  • @PaulMcKenzie 不,将其更改为 long long 仍然会溢出。所有答案都采用 mod 1e9+7 表示,它可以在 int 上表示,所以这仍然不是问题,但即使将 int 更改为 long long 也不会改变溢出。

标签: c++ algorithm dynamic-programming integer-overflow


【解决方案1】:

我终于找到了答案。我在这里添加它以完成。

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;
    }
};

【讨论】:

  • 这是有道理的。 adaptation I've used for this 源自关于 leet-code 的 outstanding k-inverse-pairs 文章,在第一步中添加了模因子。当您发布此答案时,我刚刚注意到您的答案丢失了,所以+1,先生。很高兴你修好了。
  • @WhozCraig 有趣的是,我几次浏览了他们的解决方案并摸不着头脑,因为我认为我的解决方案正是显示的那个。终于弄清楚自己的错误后,我回到了文章,发现这确实是我的解决方案和他们的解决方案之间的唯一区别:)
猜你喜欢
  • 1970-01-01
  • 2018-08-21
  • 1970-01-01
  • 1970-01-01
  • 2019-06-15
  • 2021-09-04
  • 2013-12-20
  • 2012-08-09
  • 1970-01-01
相关资源
最近更新 更多