洛谷 P2513 [HAOI2009]逆序对数列
題目描述
對于一個數列{ai},如果有i<j且ai>aj,那么我們稱ai與aj為一對逆序對數。若對于任意一個由1~n自然數組成的數列,可以很容易求出有多少個逆序對數。那么逆序對數為k的這樣自然數數列到底有多少個?
輸入輸出格式
輸入格式:
?
第一行為兩個整數n,k。
?
輸出格式:
?
寫入一個整數,表示符合條件的數列個數,由于這個數可能很大,你只需輸出該數對10000求余數后的結果。
?
輸入輸出樣例
輸入樣例#1:4 1 輸出樣例#1:
3
說明
樣例說明:
下列3個數列逆序對數都為1;分別是1 2 4 3 ;1 3 2 4 ;2 1 3 4;
測試數據范圍
30%的數據 n<=12
100%的數據 n<=1000,k<=1000
?
一道簡單題,但我覺得可以做到更大的數據,比方說加兩個0
從小到大考慮每一位,先考慮1,如果1位于i這個位置,那1與1~i-1這些位置的每一個數都會產生一個逆序對,與i+1~n這些位置的數都不會產生逆序對,至于具體每個數字是什么對于1的貢獻沒有影響
然后從排列里把1去掉,變成一個2~n的排列,這個排列與1~n-1的排列是等價的,于是問題轉化成了一個較小的問題
然后可以dp
dp[i][j]表示1~i的排列,要有j個逆序對的方法數,枚舉當前位置產生的逆序對來轉移,這個東西本來是nk^2的,但是發現一個位置轉移的時候是連續的一段,用前綴和優化去掉一個k即可
其實這個問題等價于有n個帶編號的盒子排成一列,一共放k個球,標號為i的盒子里不能放超過i-1個球,求方法總數,這應該是有更好的做法的
UPD1:這個東西的生成函數是 $ (1)(1+x)(1+x+x^2)(1+x+x^2+x^3)...(1+x+x^2+...+x^{n-1}) $ 即 $ \prod_{p=1}^{n}\sum_{q=0}^{p-1}x^q?$ ,這個形式過于美妙讓人很難不認為它有一個優美的通解
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <algorithm> 5 #include <string> 6 #include <cstring> 7 #include <cmath> 8 #include <map> 9 #include <stack> 10 #include <set> 11 #include <vector> 12 #include <queue> 13 #include <time.h> 14 #define eps 1e-7 15 #define INF 0x3f3f3f3f 16 #define MOD 10000 17 #define rep0(j,n) for(int j=0;j<n;++j) 18 #define rep1(j,n) for(int j=1;j<=n;++j) 19 #define pb push_back 20 #define mp make_pair 21 #define set0(n) memset(n,0,sizeof(n)) 22 #define ll long long 23 #define ull unsigned long long 24 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt) 25 #define max(a,b) (a>b?a:b) 26 #define min(a,b) (a<b?a:b) 27 #define print_runtime printf("Running time:%.3lfs\n",double(clock())/1000.0) 28 #define TO(j) printf(#j": %d\n",j); 29 //#define OJ 30 using namespace std; 31 const int MAXINT = 100010; 32 const int MAXNODE = 100010; 33 const int MAXEDGE = 2*MAXNODE; 34 char BUF,*buf; 35 int read(){ 36 char c=getchar();int f=1,x=0; 37 while(!isdigit(c)){if(c=='-') f=-1;c=getchar();} 38 while(isdigit(c)){x=x*10+c-'0';c=getchar();} 39 return f*x; 40 } 41 char get_ch(){ 42 char c=getchar(); 43 while(!isalpha(c)) c=getchar(); 44 return c; 45 } 46 //------------------- Head Files ----------------------// 47 48 int n,k; 49 int dp[10010],sum[10010]; 50 void get_input(); 51 void work(); 52 int main() { 53 get_input(); 54 work(); 55 return 0; 56 } 57 void work(){ 58 fill(sum,sum+k+1,1); 59 for(int i=2;i<=n;i++){ //box no i,can take 0~i-1 60 rep0(j,k+1){ 61 dp[j] = (j-i+1>0?sum[j]-sum[j-i]:sum[j]); 62 } 63 sum[0]=dp[0]; 64 rep1(j,k){ 65 sum[j]=(sum[j-1]+dp[j])%MOD; 66 } 67 } 68 printf("%d\n",(dp[k]+MOD)%MOD); 69 } 70 void get_input(){ 71 n=read();k=read(); 72 }?
轉載于:https://www.cnblogs.com/LoveYayoi/p/6921138.html
總結
以上是生活随笔為你收集整理的洛谷 P2513 [HAOI2009]逆序对数列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 互联网协议入门 : 用户 ------
- 下一篇: jconsole命令(Java Moni