[2020牛客暑期多校训练营第五场] D. Drop Voicing 思维+LIS

题目链接:D.Drop Voicing

这个题多亏队友的思路才让我醍醐灌顶,有解可寻。

题意

给你n个数的一种排列,对这个数列有两种操作。

  • [第一种] Drop-2: 把 第 二 高 位 移 到 最 低 位 , 如 p n − 1 , p 1 , p 2 , . . . . . , p n − 2 , p n {把第二高位移到最低位,如p_{n-1},p_1,p_2,.....,p_{n-2},p_{n}} pn1,p1,p2,.....,pn2,pn
  • [第二种] Invert: 把 最 低 位 移 到 最 高 位 , 如 p 2 , p 3 , . . . . . , p n − 1 , p n , p 1 {把最低位移到最高位,如p_2,p_3,.....,p_{n-1},p_{n},p_1} p2,p3,.....,pn1,pn,p1

任意连续的的Drop-2操作被称为一个muti-drop,问如何操作使得排列转变为1,2,…,n,并且要求muti-drop的数量最少。

题解

我们来看这两个操作,第一种:可以看出与 p n {p_n} pn无关,只是前n-1个数字的循环排列,第二种是这n个数字的循环排列。
循环排列: 原 序 列 : p 1 , p 2 , . . . . , p n , 循 环 排 列 后 : p i , p i + 1 , . . . , p n , p 1 , p 2 , . . , p i − 1 {原序列:p_1,p_2,....,p_n,循环排列后:p_i,p_{i+1},...,p_n,p_1,p_2,..,p_{i-1}} :p1,p2,....,pnpi,pi+1,...,pn,p1,p2,..,pi1

此时队友给了我一种思路,这两种操作可以合并为一个操作,就是将最后的一个数字 p n {p_n} pn插入到前(n-1)个数的任意位置。将插入的位置通过第一种操作移动到(n-1)个数里的最高端,然后通过第二种操作将第一个数移动到最高端就达到了插入操作。

这样我们可以通过计算最长上升子序列个数,然后用(长度-最长上升子序列个数)= 要插入的最少数字个数 = min(muti-drop)

由于原数列可以通过第二种操作进行循环排列,所以我们应枚举出每一种循环排列的情况,然后分别求出最长上升子序列的值,取其中的最大值,来保证(长度-最长上升子序列个数)min,来达到 min(muti-drop)。

代码
int p[maxn];
int dp[maxn],g[maxn],n;
int lis(vector<int> a)
{
	for(int i=1;i<=n;i++) g[i]=inf;
    int maxx=-1;
	for(int i=0;i<a.size();i++)
	{
		int k=lower_bound(g+1, g+n+1, a[i])-g;
		dp[i]=k;
		g[k]=a[i];
        maxx=max(maxx,dp[i]);
	}
	return maxx;
}
int main()
{
	cin >> n;
	for(int i=0;i<n;i++) cin >> p[i];
	int maxx=-1;
	for(int i=0;i<n;i++)
	{
		vector<int> a;
		for(int j=i;j<i+n;j++) a.push_back(p[j%n]);
		maxx=max(maxx,lis(a));
	}
	cout << n-maxx << endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值