題意:
逆序對指在乙個序列中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...