Codeforces Round #729 (Div. 2) E. Abnormal Permutation Pairs(dp+逆序对)

题目

你需要构造两个长度为n的排列,分别记为p,q,满足:

①p的字典序比q的字典序小

②p的逆序对比q的逆序对多

答案对mod(1<=mod<=1e9)取模

easy version:n<=50

hard version:n<=500

思路来源

官方题解

题解1

f[i][j]:表示长度为i,逆序对为j对的方案数,枚举第i位填的数,

考虑1-i时的从小到大的rank几,比如rank为j,则[j+1,i]与其产生了j-i个逆序对

sum[i][j]:表示f的前缀和

g[i]:表示长度为i的排列,第一个位置处p<q,但是整个排列总逆序对数p>q的方案数

算g的时候,枚举第一个位置p填数k,q填数l(k<l),再枚举p在这i位共有w个逆序对,

则p序列后i-1位有w-k个逆序对,q序列后i-1位需要少于w-l个逆序对

ans[i]:表示长度为i,满足p字典序小于q,且总逆序对数>q的方案数

考虑长度为i的ans怎么计算,

要么第一位两个数是相等的,有i种选法,从ans[i-1]转移

要么是不等的,从g[i]转移

题解2

待补

代码1(n<=50):

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=51,M=1255;
int n,mod,f[N][M],sum[N][M],g[N],ans[N];
//f[i][j]:长度为i 逆序对为j对的方案数 枚举最后一个值产生的逆序对数
//sum[i][j]:前缀和
//g[i]:长度为i 第一个位置p<q 保证总逆序对数p>q的方案数
//ans[i]:长度为i p<q 保证总逆序对数p>q的方案数
void add(int &x,int y){
	x+=y;
	x%=mod;
}
int main(){
	scanf("%d%d",&n,&mod);
	add(f[1][0],1);
	for(int j=1;j<M;++j){
		add(sum[1][j],1);
	}
	for(int i=2;i<=n;++i){
		for(int j=0;j<M;++j){
			add(f[i][j],sum[i-1][j]);
			if(j-i>=0)add(f[i][j],mod-sum[i-1][j-i]);
			sum[i][j]=f[i][j];
			if(j-1>=0)add(sum[i][j],sum[i][j-1]);
		}
	}
	for(int i=1;i<=n;++i){//长度为i 枚举第一位p<q 
		for(int k=1;k<=i;++k){//p
			for(int l=k+1;l<=i;++l){//q
				for(int w=0;w<M;++w){//后面i-1位 p有w-(k-1)对 q少于w-(l-1)对
					if(w-(l-1)-1<0)continue; 
					add(g[i],1ll*f[i-1][w-(k-1)]*sum[i-1][w-(l-1)-1]%mod);
				}
			} 
		}
	}
	for(int i=2;i<=n;++i){
		add(ans[i],(g[i]+1ll*i*ans[i-1]%mod)%mod);
	}
	printf("%d\n",ans[n]);
	return 0;
} 

代码2(n<=500):

待补

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值