LeetcodeのK Inverse Pairs Array


タイトル:
Given two integers  n  and  k , find how many different arrays consist of numbers from  1  to  n  such that there are exactly  k  inverse pairs.
We define an inverse pair as following: For  ith  and  jth  element in the array, if  i j and  a[i]  >  a[j]  then it's an inverse pair; Otherwise, it's not.
Since the answer may be very large, the answer should be modulo 109 + 7.
Example 1:
Input: n = 3, k = 0
Output: 1
Explanation: 
Only the array [1,2,3] which consists of numbers from 1 to 3 has exactly 0 inverse pair.


Example 2:
Input: n = 3, k = 1
Output: 2
Explanation: 
The array [1,3,2] and [2,1,3] have exactly 1 inverse pair.

Note:
  • The integer  n  is in the range [1, 1000] and  k  is in the range [0, 1000].

  • コード:
    方法1-タイムアウト、直接的な考え方:
    class Solution {
    public:
        int kInversePairs(int n, int k) {
        
        vector> v(n + 1, vector(k+1, 0));
        v[1][0] = 1;
        for (int i = 2; i <= n; i++) {
            for (int j = 0; j <= k; j++) {
                int n = j;
                while (n>=0&&n >= j-i+1) {
                    v[i][j]=(v[i][j]+v[i-1][n])%1000000007;
                    n--;
                }
    
            }
        }
        return v[n][k];
        }
    };

    方法2——時間最適化を行った後:
    class Solution {
    public:
        int kInversePairs(int n, int k) {
            int M = 1000000007;
            vector> dp(n + 1, vector(k + 1, 0));
            dp[0][0] = 1;
            for (int i = 1; i <= n; ++i) {
                dp[i][0] = 1;
                for (int j = 1; j <= k; ++j) {
                    dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % M;
                    if (j >= i) {
                        dp[i][j] = (dp[i][j] - dp[i - 1][j - i] + M) % M;
                    }
                }
            }
            return dp[n][k];
        }
    };

    アイデア:いくつかの小さなtrickを使用します.
    dp[n][k] = dp[n - 1][k] + dp[n - 1][k-1] + ... + dp[n - 1][k - n + 1]
    kの代わりにk+1を使用して、次のようにすることができます.
    dp[n][k+1] = dp[n - 1][k+1] + dp[n - 1][k] + ... + dp[n - 1][k + 1 - n + 1]
    2番目の式から1番目の式を減算すると、次のようになります.
    dp[n][k+1] = dp[n][k] + dp[n - 1][k+1] - dp[n - 1][k - n + 1]
    k+1をkに戻すと、次のようになります.
    dp[n][k] = dp[n][k-1] + dp[n - 1][k] - dp[n - 1][k - n]
    k>=nの場合,最後の項の配列座標が非負の数になり,最後の項に値があることが分かったので,再更新する際にはkとnの関係を判断するだけで,k>=nの場合,最後の項を減算するという繰返し式がより効率的に計算され,サイクルが減少する