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;
100%的数据 n<=1000,k<=1000
题解
前缀和优化dp.
由于逆序对个数与每个数位置有关,所以我开始时想dp[i][j]表示第i个位置放j这个数的最优解。但没办法转移。。
后来看题解知道了前缀和优化dp的东西,dp[i]][j]表示数列中有i-1个数,把第i个数放进去逆序对为j的方案数,由于i>前面的所有数,所以枚举原来i-1时逆序对数k(max(j-i+1,0),j)时i-1-k就是增加的逆序对个数,
所以dp[i][j]=sigmadp[i-1][k]。由于是连续区间的和,所以可以用前缀和优化把三维变成二维,当j-i小于0时i-1的逆序对数可以是0,就直接是一个前缀和,当j-i>=0时就是中间一段区间的和了,所以要减去dp[i-1][j-i]再赋值;最后输出dp[n][k]就好了。
样例说明:
下列3个数列逆序对数都为1;分别是1 2 4 3 ;1 3 2 4 ;2 1 3 4;
100%的数据 n<=1000,k<=1000
题解
前缀和优化dp.
由于逆序对个数与每个数位置有关,所以我开始时想dp[i][j]表示第i个位置放j这个数的最优解。但没办法转移。。
后来看题解知道了前缀和优化dp的东西,dp[i]][j]表示数列中有i-1个数,把第i个数放进去逆序对为j的方案数,由于i>前面的所有数,所以枚举原来i-1时逆序对数k(max(j-i+1,0),j)时i-1-k就是增加的逆序对个数,
所以dp[i][j]=sigmadp[i-1][k]。由于是连续区间的和,所以可以用前缀和优化把三维变成二维,当j-i小于0时i-1的逆序对数可以是0,就直接是一个前缀和,当j-i>=0时就是中间一段区间的和了,所以要减去dp[i-1][j-i]再赋值;最后输出dp[n][k]就好了。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=10000;
int dp[1005][1005];
int main(){
int n,k,sum;
scanf("%d%d",&n,&k);
dp[0][0]=1;
for(int i=1;i<=n;i++){
sum=0;
for(int j=0;j<=k;j++){
if(j-i>=0) sum=(sum-dp[i-1][j-i]+mod)%mod;
sum=(sum+dp[i-1][j])%mod;
dp[i][j]=sum;
}
}
printf("%d\n",dp[n][k]);
return 0;
}