luogu 1521 求逆序對

2022-05-16 21:15:37 字數 1499 閱讀 9852

題意:

逆序對指在乙個序列中ai>aj && i < j,也就是一前一後兩個數,當大的在前面的時候即算一對。

題目求在乙個由1…n組成的序列中逆序對為k的序列的個數。

出題人很良心,不需要寫高精度,答案對10000取模即可。

思路:

這道題的前面其實還有一道很類似的題,也是求逆序對。不同的是那道題給定了序列求逆序對的個數,而這道題則相反。那道題的方法即merge sort。儘管兩題很類似,但是方法卻截然不同。

憑感覺,這應該是一道動規的題。長度為n-1的序列與長度為n的序列只差乙個n,而由於n出現的逆序對也很好求:n在第i個就會相比於原序列多出n-i個逆序對。如此,那看來是動規無疑了。

狀態轉移方程:若長度為n的序列要求有k個逆序對,那麼他可以從長為n-1的序列中選取有k-n+1到k個逆序對的部分。道理很簡單n的加入最多使原序列增加n-1個逆序對(即放在第乙個的時候,與後面n-1個數構成逆序對),所以要從x[n-i][p]變到x[n][k],p屬於[k-n+1,k]。那麼轉移方程式就很好寫了:

for(unsigned i = 2; i != n+1; ++i)

}}

優化:

這是乙個o(n^3)的演算法,很慢。我們觀察最內層迴圈,發現它很多餘,因為總是重複操作。dp[i][j-1]和dp[i][j]當i-j+1>0的時候,中間部分完全相同,只是掐頭增尾的問題。由此我們可以有第一種優化:dp[i][j] = dp[i][j-1]-dp[i-1][j-i]+dp[i-1][j];(j-i >-1)

當然也可以直接採用字首陣列和的方式將這段迴圈優化掉,到o(n^2)。

(後面的**採取的是這一種)

源**的讀入是多組資料。

源**:

#include 

#define maxn 1005

#define mod 10000

//#define debug

#ifdef debug

#define debug(...)printf(__va_args__);

#else

#define debug(...)

#endif

using namespace std;

int n[15], k[15], dp[maxn][maxn*10];

void dp(int n, int k)

for(int i = 2; i != n+1; ++i)

debug("\n");

}return ;

}int main()

dp(maxn, maxk);

for(unsigned i = 0; i != times; ++i)

return

0;}

箜瑟_qi 2017.04.27 15:01

樹狀陣列求逆序對與luogu1908

今天上午,我完成了樹狀陣列求逆序對 1 的學習,並完成了luogu1908的程式設計與除錯,以下是一些記錄與感想 樹狀陣列求逆序對的中心思想是 1 樹狀陣列c a i 記錄a i 出現的次數,然後利用樹狀陣列求小於a i 的數的個數s i 2 2 用i s i 表示輸入到當前時,大於a i 的數的個...

歸併求逆序對

求這個逆序對只需要在歸併排序的 中加一句即可。感覺自己有點說不清楚,隨手附上別人的詳細解釋,請戳 詳細介紹 include include includeusing namespace std int a 1000000 int b 1000000 int sum 0 void merge int ...

1311 求逆序對

給定乙個序列a1,a2,a n,如果存在i i a j,那麼我們稱之為逆序對,求逆序對的數目。第一行為n,表示序列長度,接下來的n行,第i 1行表示序列中的第i個數。所有逆序對總數。432 32 3 n 105,a i 105 if 1 include include include include...