P2513 逆序对数列-前缀和优化dp

题目描述
对于一个数列{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

思路

  1. 排列题一般考虑把数从小到大插入到序列中
  2. dp[i][j]表示填到 i ,之前有 j 个逆序对的方案数
  3. 因为i比之前的数都到,不同的插入可以产生0~ i-1个逆序对。
    所以dp[i][j]+=dp[i-1][k] (j-i+1<=k<=j)
  4. 用前缀和优化dp[i-1][k]=sum[j]-sum[ max(j-i,0) ]
// brief
const int mod=10000;
int f[1100][1100];
int main()
{
	int n,m;
	cin>>n>>m;
	f[1][0]=1;
	for(int i=2;i<=n;i++)// 填到i位 
	{
		for(int j=0;j<=m;j++)// j个逆序对 
		{
			for(int k=0;k<i;k++)// 枚举i填在哪里 
			{
				f[i][j]=(f[i][j]+f[i-1][j-k])%mod;
			}
		}
	}
	cout<<f[n][m]<<endl;
	return 0;
}

using namespace std;
const int mod=10000;
int f[1100][1100];
int main()
{
	int n,k;
	cin>>n>>k;
	f[1][0]=1;
	for(int i=2;i<=n;i++)// 填到i位 
	{
		int sum=0;
		for(int j=0;j<=k;j++)// j个逆序对 
		{
			sum=(sum+f[i-1][j])%mod;
			f[i][j]=sum;
			if(j-i+1>=0) sum=(sum-f[i-1][j-i+1]+mod)%mod;
		}
	}
	cout<<f[n][k]<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值