【BOI2007】Ranklist Sorting

【BOI2007】Ranklist Sorting

Description

有一个长为n的排列p

每次可以选两个位置i,j,然后将pi放到j的位置上,代价为i+j

求将排列变为降序的最小代价(原题要求构造方案)

Input

第一行一个数n

然后读入排列

Output

一行一个数表示答案

Sample Input

4
2 3 1 4 

Sample Output

8

Data Constraint

1n2000

Solution

OI倒退十年是吧

首先为了方便理解,可以把降序看成升序

每个数分为两种:动与不动

显然动点只会移动一次

然后可以通过调整证明:动点从大到小/从小到大移到对应位置一定不会更劣

考虑dp

fi,j表示从大到小填到ii要放在原序列j的位置上

此时i+1n已经按升序排好,1i的相对顺序与原序列相同

那么对于每个数,我们可以计算出其当前位置,记为nowi

i动时,i一定要放在i+1的前面,即fi,j=min(fi,j,fi+1,j+nowi+nowj)

i不动时,这一步决策会对后面的贡献值造成影响,但是我们可以将其提前计算

具体来说,设posi表示i在原序列中的位置

对于枚举的jk[posi+1,j1]k一定会跨过i,此时[pk+1,i]这些数全部出现

对其造成的影响就是max(ipk,0)

于是有fi,posi=min(fi,posi,fi+1,j+k=posi+1j1max(ipk,0))

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 2010

int f[N][N],p[N],n,pos[N],ans;

int main(){
	scanf("%d",&n);
	F(i,1,n)scanf("%d",&p[i]),p[i]=n-p[i]+1,pos[p[i]]=i;
	p[n+1]=pos[n+1]=n+1;
	memset(f,127,sizeof(f));
	ans=f[0][0];
	f[n+1][n+1]=0;
	Fd(i,n,1){
		int p1=1,p2=1;
		F(j,1,i-1)p1+=pos[j]<pos[i];
		F(j,1,n+1){
			p2+=p[j]<i;
			f[i][j]=min(f[i][j],f[i+1][j]+p1+p2);
		}
		int sum=0;
		F(j,pos[i]+1,n+1){
			f[i][pos[i]]=min(f[i][pos[i]],f[i+1][j]+sum);
			sum+=max(i-p[j],0);
		}
	}
	F(i,1,n+1)ans=min(ans,f[1][i]);
	printf("%d",ans);
	return 0;
}
posted @   冰雾  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示