1. 程式人生 > >51nod 1020 逆序排列 (DP_好題)

51nod 1020 逆序排列 (DP_好題)

在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。 如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序數是4。 1-n的全排列中,逆序數最小為0(正序),最大為n*(n-1) / 2(倒序) 給出2個數n和k,求1-n的全排列中,逆序數為k的排列有多少種? 例如:n = 4 k = 3。 1 2 3 4的排列中逆序為3的共有6個,分別是: 1 4 3 2 2 3 4 1 2 4 1 3 3 1 4 2 3 2 1 4 4 1 2 3 由於逆序排列的數量非常大,因此只需計算並輸出該數 Mod 10^9 + 7的結果就可以了。 Input
第1行:一個數T,表示後面用作輸入測試的數的數量。(1 <= T <= 10000)
第2 - T + 1行:每行2個數n,k。中間用空格分隔。(2 <= n <= 1000, 0 <= k <= 20000)
Output
共T行,對應逆序排列的數量 Mod (10^9 + 7)
Input示例
1
4 3
Output示例
6

設f(n,k)表示n個數的排列中逆序數個數為k的排列數。

最大的數n可能會排在第n-i位,從而產生i個與n有關的逆序對,去掉n之後,剩下的n-1個數的排列有k-i個逆序對。所以,f(n,k)=求和(f(n-1,k-i))(0<=i<n)。 同理有f(n,k-1)=求和(f(n-1,k-1-i))(0<=i<n)。 兩式相減,可得f(n,k)-f(n,k-1)=f(n-1,k)-f(n-1,k-n)。 遞推公式為f(n,k)=f(n,k-1)+f(n-1,k)-f(n-1,k-n)。 然後動態規劃可得。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
int f[1111][22222];
const int mod=1e9+7;
void init()
{
	int i,j;
	for(i=1;i<=1000;i++) f[i][0]=1;
	for(i=2;i<=1000;i++) {
		for(j=1;j<=i*(i-1)/2&&j<=20000;j++){
			f[i][j]=(f[i][j-1]+f[i-1][j])%mod;
			if(j-i>=0) f[i][j]=((f[i][j]-f[i-1][j-i])%mod+mod)%mod;
		}
	}
}
int main()
{
	int t,i,j,n,m;
	init();
	scanf("%d",&t);
	while(t--) {
		scanf("%d%d",&n,&m);	
		printf("%d\n",f[n][m]);	
	}
	return 0;
}


相關推薦

51nod 1020 排列 (DP_)

在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。 如2 4 3 1中,2 1,4 3,4 1,3

51nod 1020 排列【Dp+思維遞推優化】

基準時間限制:2 秒 空間限制:131072 KB 分值: 80 難度:5級演算法題 在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。 如2 4 3 1中,2

51nod 1020 排列

quest 技術分享 logs class tps return mod div tput 1020 逆序排列 基準時間限制:2 秒 空間限制:131072 KB 分值: 80 難度:5級算法題 收藏 關註 在一個排列中,如果一對數的前後位置與大小順序相

51nod 1020 排列 遞推DP

公式 problem 一個 def 分別是 nbsp 最大 nco 例如 1020 逆序排列 基準時間限制:2 秒 空間限制:131072 KB 分值: 80 難度:5級算法題 收藏 關註 在一個排列中,如果一對數的前後位置與大

51Nod 1020 - 排列(DP)

題目連結 http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1020 【題目描述】 在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排

51nod 1020 排列 (DP)

基準時間限制:2 秒 空間限制:131072 KB 在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。 如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序數是4。 1

51nod 1020 排列(dp)

想破腦袋也想不到。。。。 先定義狀態,dp[i][j]表示i個數字的全排列中逆序數為j的序列的個數 剛開始做的時候,拿筆畫了一會,憑著感覺蒙了個狀態轉移方程:dp[i][j]=dp[i-1][j]+

51nod 1020排列

題解: 這題肯定是DP題。定義f[i][j]表示前i個數,產生j組逆序對的排列數量。那麼顯然可以想到n^3的做法,就是列舉當前第i個數放在哪裡。但是這樣是會超時的。但是我們可以稍加推導,最後得出f[i][j]=f[i][j-1]+f[i-1][j]-f

51nod 1020 排列【DP】

Description 在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。 如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序數是4。 1-n的全排列中

51nod 1270 陣列的最大代價 (DP_)

陣列A包含N個元素A1, A2......AN。陣列B包含N個元素B1, B2......BN。並且陣列A中的每一個元素Ai,都滿足1 <= Ai <= Bi。陣列A的代價定義如下

10.14 將n個數按輸入輸出順序的排列,用函數實現

bdn r+ mvt b2c odr ack thp zip evb 將n個數按輸入輸出順序的逆序排列,用函數實現。 #include <stdio.h> int main(){ int n,i; void reverse(int * num

51nod1020 排列

amp 直接 技術分享 span ring queue std iostream scanf t<=10000個問,每次問n<=1000的全排列中逆序數對為k<=10000個的有多少,mod 1e9+7。 直接dp,$f(i,j)$--i的全排列中逆序數對

[USACO17FEB] Why Did the Cow Cross the Road I P (樹狀數組求對 易錯)

-h 特殊性 另一個 %d .org class data 操作 efi 題目大意:給你兩個序列,可以序列進行若幹次旋轉操作(兩個都可以轉),對兩個序列相同權值的地方連邊,求最少的交點數 記錄某個值在第一個序列的位置,再記錄第二個序列中某個值 在第一個序列出現的位置 ,求逆

將n個數按輸入時順序的排列,用函式實現(指標)

#include <stdio.h> void reverse(int a[],int n) { int *p;   for(p=a+n-1;p>=a;p--)        &nb

一段讀取檔案,排列的lua指令碼

local method = ngx.var.request_method; local headers = ngx.req.get_headers(); local uri_args = ngx.r

資料庫SQL實戰 —— 查詢employees表所有emp_no為奇數,且last_name不為Mary的員工資訊,並按照hire_date排列

時間限制:1秒 空間限制:32768K 題目描述 查詢employees表所有emp_no為奇數,且last_name不為Mary的員工資訊,並按照hire_date逆序排列 CREATE TABL

劍指offer——字串的排列,擴充套件也很,全排列的演算法)

題目描述 輸入一個字串,按字典序打印出該字串中字元的所有排列。例如輸入字串abc,則打印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。 輸入描述: 輸入一個字串,長度不超過9(可能有字元重複),字元只包括大小寫字

藍橋杯 演算法提高 ADV-103 排列 迴圈語句 陣列操作

演算法提高 逆序排列 時間限制:1.0s 記憶體限制:512.0MB 問題描述   編寫一個程式,讀入一組整數(不超過20個),並把它們儲存在一個整型陣列中。當用戶輸入0時,表示輸入結束。然後程式將把這個陣列中的值按逆序重新存放,並打印出來。例如:假設使用者輸入了一組資料:7 19

JAVA陣列學習之一:對一維陣列進行排列

Java中的陣列必須先初始化,然後才能使用。所謂初始化,就是為陣列中的元素分配記憶體空間,併為元素賦值。 陣列的初始化方式: 動態初始化:初始化時只指定陣列長度,由系統為陣列分配初始值。 靜態初始化:

9.28機試 定義兩個陣列,首先把兩個數組合併成一個新陣列,然後把新陣列中的所有元素排列

public class Demo7 { public static void main(String[] args) { int[]array1 = new int[]{10,20,30};