1. 程式人生 > 其它 >逆序對數列(DP+字首和)

逆序對數列(DP+字首和)

又是DP又是字首和,小白做題太慢了/(ㄒoㄒ)/~~
洛谷P2513,Acwing2692

題目

對於一個數列 {ai},如果有 i<j 且 ai>aj,那麼我們稱 ai 與 aj 為一對逆序對數。
若對於任意一個由 1∼n 自然陣列成的數列,可以很容易求出有多少個逆序對數。
那麼逆序對數為 k 的這樣自然數數列到底有多少個?

輸入輸出

輸入:共一行,兩個整數 n,k。
輸出:輸出一個整數,表示符合條件的數列個數,由於這個數可能很大,你只需輸出該數對 10000 求餘數後的結果。

思路

求1-n的全排列中逆序對數為k的排序,可用動態規劃來做。
動態規劃陣列:dp[i][j](0 <= j <= k)為1-i個數的全排列中逆序對數為j的方案數。
可以由1-(i-1)得出的結果來推斷 1-i的結果
將i插入1-(i-1)的排列中,會增加逆序對
動態規劃的初始化結果為dp[i][0] = 1


考慮i放置的位置,放i-1個位置都能增加逆序對數量
當i插在1-(i-1)的排列最後一個位置時,沒有增加逆序對數,dp[i][j] += dp[i-1][j]
當i插在1-(i-1)的排列倒數第二個位置時,增加了一個逆序對數,dp[i][j] += dp[i-1][j-1]
......
當i插在1-(i-1)的排列倒數第m個位置時,增加了m-1個逆序對數,dp[i][j] += dp[i-1][j-m+1]
......
當i插在1-(i-1)的排列倒數第j+1個位置時,增加了j個逆序對數,dp[i][j] += dp[i-1][0]
注意:i最多能在1-(i-1)的序列上貢獻i-1個逆序對

當j>=i-1時,dp[i][j]不能加上 dp[i-1][0-(j-i+1]這一段
時間複雜度:不經任何優化的時間複雜度是O(n^3),會超時

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;
int dp[N][N];

int main()
{
    int n,k;
    cin >> n >> k;
    for (int i = 1; i <= n; i ++ ) dp[i][0] = 1;
    for (int i = 2; i <= n; i ++ ){ //列舉n個數
        for(int j = 1;j <= k;j ++){  //列舉逆序對的個數
            for(int m = max(0,j-i+1);m <=j;m++){
                dp[i][j] = (dp[i][j] + dp[i-1][m])%10000;
            }
        }
    }
    cout << dp[n][k];
}

用字首和優化

上述演算法時間複雜度:不經任何優化的時間複雜度是O(n^3),會超時
用sum記錄dp[i-1][j],前j個之和,並當j>=i-1時,sum減去dp[i-1][j-i+1],相當於上面那種演算法,沒有把dp[i-1][0-(j-i+1]這一段算進去。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;
int dp[N][N];

int main()
{
    int n,k;
    cin >> n >> k;
    for (int i = 1; i <= n; i ++ ) dp[i][0] = 1;
    for (int i = 2; i <= n; i ++ ){ //列舉n個數
        int sum = 0;
        for(int j = 0;j <= k;j ++){  //列舉逆序對的個數
            sum = (sum + dp[i-1][j]) % 10000;
            dp[i][j] = sum;
            if(j >= i - 1)
                sum = (sum - dp[i-1][j-i+1] + 10000) % 10000;
        }
    }
    cout << dp[n][k];
}
作者:inss!w! 出處:https://www.cnblogs.com/Hfolsvh/ 版權宣告:本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協議。轉載請註明出處!