[HAOI2009]逆序对数列

题目描述

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

输入输出格式

输入格式:

第一行为两个整数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

题解:

算是比较好想吧.

如果dp每一位,显然不好记录状态,那么就按填数的顺序枚(从小到大一个个填)

f[i][j]表示已经填了小于等于i的数,产生的逆序对数量为j的方案数

显然现在插入的i比以前都大,那么可以产生[0,i-1]个逆序对

于是就可以枚举产生的逆序对数量k开始推了

f[i][j]+=f[i-1][j-k]

而且j-k是连续一段的和,那么可以用前缀和O(1)算出

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #define RG register
 8 using namespace std;
 9 typedef long long ll;
10 const int N=1005,mod=10000;
11 int f[N][N];ll sum[N];
12 void work()
13 {
14     int n,m;
15     scanf("%d%d",&n,&m);
16      for(int j=1;j<=m+1;j++)sum[j]=1;
17     for(RG int i=2;i<=n;i++){
18          for(RG int j=0,tmp;j<=m;j++){
19              if(j-i+1>0)tmp=j-i+1;
20              else tmp=0;
21              f[i][j]+=sum[j+1]-sum[tmp];
22              f[i][j]%=mod;
23          }
24          for(int j=1;j<=m+1;j++){
25              sum[j]=sum[j-1]+f[i][j-1];
26          }
27     }
28     printf("%d
",f[n][m]);
29 }
30 int main()
31 {
32     work();
33     return 0;
34 }
原文地址:https://www.cnblogs.com/Yuzao/p/7291416.html