[题解] P2513 [HAOI2009]逆序对数列

动态规划,卡常数


题目地址

\(F[X][Y]\)代表长度为\(X\)的序列,存在\(Y\)组逆序对的方案数量。

考虑\(F[X][i]\)\(F[X+1][i]\)转移:

  • 把数字\(X+1\)添加到序列的第\([1,X]\)号位置上,可以增加\([0,X]\)个逆序对。
  • 注意逆序对的个数不能超过\(\frac{N(N-1)}{2}\),其中\(\text{N}\)代表序列长度。

注意效率问题。

参考代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <iostream>
#define GC getchar()
#define Min(X,Y) ((X)<(Y)?(X):(Y))
#define Clean(X,K) memset(X,K,sizeof(X))
#define re register
const int Maxn = 1005 , Maxk = 1005 , P = 10000;
int F[Maxn][Maxk] , N , K /*, S[Maxn][Maxk]*/ ;
using namespace std ;
int main () {
    //  freopen ("P2513.in" , "r" , stdin) ;
    scanf ("%d%d" , &N , &K) ;
    Clean (F , 0) ,  /*Clean (S , 0) ,*/ F[0][0] = /*S[0][0] = */1 ;
    for (re int i = 0 ; i < N ; ++ i) {
        re int E1 =Min ((i * (i - 1)) / 2 , K) ;
        for (re int j = 0 ; j <= E1; ++ j) {
            re int E2 = Min (K - j , i) ;
            for (re int k = 0 ; k <= E2 ; ++ k) {
                F[i + 1][j + k] += F[i][j] ;
                while (F[i + 1][j + k] >= P) F[i + 1][j + k] -= P ;
            }
        }
    }
    printf ("%d\n" , F[N][K]) ;
    fclose (stdin) , fclose (stdout) ;
    return 0 ;
}

Thanks!

posted @ 2019-04-24 15:56  Betulaceae  阅读(156)  评论(0编辑  收藏  举报