逆序对数列(BZOJ 2431)

题目描述

对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数。若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数。那么逆序对数为k的这样自然数数列到底有多少个?

输入

 第一行为两个整数n,k。

输出

写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果。

 

样例输入

4 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的方案数 
  在i-1个数中加入一个数,新增逆序对数为0~i-1,所以f[i][j]=Σf[i-1][k] (j-i+1<=k<=j)
  时间复杂度为O(n^3),采用前缀和优化:f[i][j]=g[i-1][j]-g[i-1][j-i] 
*/ 
#include<cstdio>
#include<iostream>
#define M 1010
#define Mod 10000
using namespace std;
int f[M][M],g[M][M];
int read()
{
    char c=getchar();int flag=1,num=0;
    while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();}
    return num*flag;
}
int main()
{
    int n=read(),k=read();
    f[0][0]=1;
    for(int i=0;i<=k;i++)g[0][i]=1;
    for(int i=1;i<=n;i++)
      for(int j=0;j<=k;j++)
      {
          f[i][j]=g[i-1][j];
          if(j-i>=0)f[i][j]=(f[i][j]+Mod-g[i-1][j-i])%Mod;
          if(j)g[i][j]=g[i][j-1];
          g[i][j]+=f[i][j];
          g[i][j]%=Mod;
      }
    printf("%d",f[n][k]);
    return 0;
}
View Code

 

posted @ 2016-07-27 11:21  karles~  阅读(236)  评论(0编辑  收藏  举报