1. 程式人生 > >[luogu2513 HAOI2009] 逆序對數列 (計數dp)

[luogu2513 HAOI2009] 逆序對數列 (計數dp)

class Go 數列 += n) #define 100% ems sin

題目描述

對於一個數列{ai},如果有i

輸入輸出格式

輸入格式:
第一行為兩個整數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

f[i][j] 表示i的排列有j個逆序對數的情況數
依次插入1,2,3,4......,n
插入第i個數時:
當插在0位置時逆序對增加(i-1)組,
當插在1位置時逆序對增加(i-2)組,
......
跟據以上想法推出出動規方程:

F(i,1,n) F(j,1,k) F(l,max(1,i-j),i) 
    f[i][j]+=f[i-1][j-(i-l)];

n^3過不了,用下前綴和優化即可
code:

//By Menteur_Hxy
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include <ctime> #define M(a,b) memset(a,(b),sizeof(a)) #define F(i,a,b) for(register int i=(a);i<=(b);i++) #define LL long long using namespace std; inline LL rd() { LL x=0,fla=1; char c=‘ ‘; while(c>‘9‘|| c<‘0‘) {if(c==‘-‘) fla=-fla; c=getchar();} while(c<=‘9‘ && c>=‘0‘
) x=x*10+c-‘0‘,c=getchar(); return x*fla; } inline void out(LL x){ int a[25],wei=0; if(x<0) putchar(‘-‘),x=-x; for(;x;x/=10) a[++wei]=x%10; if(wei==0){ puts("0"); return;} for(int j=wei;j>=1;--j) putchar(‘0‘+a[j]); putchar(\n); } const int MOD=10000; const int N=1010; const int INF=0x3f3f3f3f; int n,k; int f[N][N]; int main() { n=rd(),k=rd(); f[1][0]=1; F(i,2,n) { LL sum=0; F(j,0,k) { (sum+=f[i-1][j])%MOD; f[i][j]=sum%MOD; if(j-i+1>=0) ((sum-=f[i-1][j-i+1])+MOD)%MOD; } } out(f[n][k]); return 0; }

[luogu2513 HAOI2009] 逆序對數列 (計數dp)