[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\n",f[n][m]); 29 } 30 int main() 31 { 32 work(); 33 return 0; 34 }