1. 程式人生 > >[HAOI2009]逆序對數列

[HAOI2009]逆序對數列

Description
對於一個數列{ai},如果有i aj,那麼我們稱ai與aj為一對逆序對數。若對於任意一個由1~n自然陣列成的數列,可以很容易求出有多少個逆序對數。那麼逆序對數為k的這樣自然數數列到底有多少個?

Input
第一行為兩個整數n,k。

Output
寫入一個整數,表示符合條件的數列個數,由於這個數可能很大,你只需輸出該數對10000求餘數後的結果。

Sample Input
4 1

Sample Output
3

HINT
100%的資料 n<=1000,k<=1000

二維dp

設f[i][j]表示列舉到第i個點,逆序對個數為j的方案數,利用字首和優化可以將複雜度降到\(O(n^2)\)

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1; char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=1e3,p=1e4;
int f[N+10][N+10],g[N+10][N+10];
int main(){
    int n=read(),k=read();
    f[1][0]=1;
    for (int i=0;i<=k;i++)  g[1][i]=1;
    for (int i=2;i<=n;i++){
        for (int j=0;j<=k;j++)
            if (j<i)    f[i][j]=g[i-1][j];
            else    f[i][j]=(g[i-1][j]-g[i-1][j-i]+p)%p;
        g[i][0]=f[i][0];
        for (int j=1;j<=k;j++)  g[i][j]=(g[i][j-1]+f[i][j])%p;
    }
    printf("%d\n",f[n][k]);
}