Bzoj 2431 HAOI2009 逆序对数列

Description
对于一个数列{ai},如果有i**<**j且ai>aj,那么我们称ai与aj为一对逆序对数。若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数。那么逆序对数为k的这样自然数数列到底有多少个?
Input
第一行为两个整数n,k。
Output
写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果。
Sample Input
样例输入
4 1
Sample Output
样例输出
3
样例说明:
下列3个数列逆序对数都为1;分别是1 2 4 3 ;1 3 2 4 ;2 1 3 4;
测试数据范围
30%的数据 n<=12
100%的数据 n<=1000,k<=1000

/*
暴力n^3.
30分.  
*/
#include<iostream>
#include<cstdio>
#define MAXN 10001
#define mod 1000000007
using namespace std;
int f[MAXN][MAXN],n,m;
int main() {
    scanf("%d %d",&n,&m);
    f[1][0]=1;
    for(int i=1; i<=n; i++)
        for(int j=0; j<=m; j++)
            for(int k=0; k<i; k++) 
            {
                f[i][j]+=f[i-1][j-k];
                f[i][j]%=mod;
            }
    printf("%d ",f[n][m]);
    return 0;
}
/*
中学生不能太暴力.
so  我们考虑优化.
DP暴力n^3完全能搞出来.
然后我们发现转移的时候
对于i状态只有i-1状态转移而来.
我们考虑类似于滚动数组之类的东西.
so 处理一个前缀和.
f[i][j]表示i个数j个逆序对时的方案数.
对于第i个数来说,若是递增序放置的
那么 i放置位置的后面每个数都可以与i形成一对逆序对. 
*/
#include<iostream>
#include<cstdio>
#define MAXN 10001
#define mod 1000000007
using namespace std;
long long f[MAXN][MAXN],n,m,tot;
int main() 
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
      f[i][0]=1;
    for(int i=2;i<=n;i++)
    {
      tot=f[i-1][0];
      for(int j=1;j<=m;j++)
        {
            if (j>=i) tot-=f[i-1][j-i];
            tot+=f[i-1][j];
            f[i][j]=tot%mod;
        }
    }
    printf("%d",f[n][m]);
    return 0;
}
posted @ 2016-06-26 21:31  nancheng58  阅读(103)  评论(0编辑  收藏  举报