bzoj2457

/*
此题我先开始考虑的是每个数都不同,那么贪心就好。
然后由于有相同的那么我们考虑怎样消除,最后发现我贪心没法搞重换思路用了dp,但是贪心的这个错误思路
却给了我一定的启发。
此题考虑最后的情况他一定是一段一段的每段都是相同的数字,
那么不同段之间的接口能缝合越多,答案越优秀。
注意每段都是最先一个数进去,然后后面的数按照位置重小到大排
每段的接口能缝合主要是看一些相对关系:
比如:
 一堆数排序后:
 1 1 2 2
 1这一段对应的pos.max=3 pos.min=1
 2是 pos.max=4 pos.min=2
 元数列是
 1 2 1 2
 11这一段可以看成是pos.min在右 pos.max在左,这样他放的时候是从左到右的 也就是'<-'这个方向
 同理也可以是'->'这个方向 也就是pos.min先放在左边 然后pos.max放在右边
 重点是一定都是先放pos.min然后你再选方向,你不能两个方向都选的。。。这样不利于我们dp,最重要的是重贪心的角度看你这样放不好
 然后什么时候缝合你自己想想把~~(先重贪心的角度看看如果实在不理解~~)
 dp[i][0]表示第i大的重左往右放
 dp[i][1]表示第i大的重右往左放
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
struct rk
{
	int maxp, minp;
};
rk rkk[200020];
struct v
{
	int pos;
	ll value;
};
v value[200020];
int n;
int dp[200020][2];
bool com(v a, v b)
{
	return a.value < b.value;
}
int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%lld", &value[i].value);
		value[i].pos = i;
	}
	sort(value, value + n,com);
	for (int i =1; i <=n; i++)
		rkk[i].maxp = -1, rkk[i].minp = 1000000000;
	int rank = 1;
	rkk[rank].maxp = value[0].pos;
	rkk[rank].minp = value[0].pos;
	for (int i = 1; i < n; i++)
	{
		if (value[i].value > value[i - 1].value)
			rank++;
		rkk[rank].maxp = max(value[i].pos, rkk[rank].maxp);
		rkk[rank].minp = min(value[i].pos, rkk[rank].minp);
	}
	for (int i = 1; i <= rank; i++)
	{
		for (int j = 0; j < 2; j++)
		{
			dp[i][j] = 1000000000;
		}
	}
	dp[1][0] = dp[1][1] = 1;
	for (int i = 1; i < rank; i++)
	{
		if (rkk[i + 1].minp > rkk[i].maxp)
			dp[i + 1][0] = min(dp[i + 1][0], dp[i][0]);
		else
			dp[i + 1][0] = min(dp[i + 1][0], dp[i][0] + 1);
		dp[i + 1][1] = min(dp[i + 1][1], dp[i][0] + 1);
		
		dp[i + 1][0] = min(dp[i][1], dp[i + 1][0]);
		if (rkk[i].minp>rkk[i + 1].maxp)
			dp[i + 1][1] = min(dp[i + 1][1], dp[i][1]);
		else
			dp[i + 1][1] = min(dp[i + 1][1], dp[i][1] + 1);
	}
	printf("%d\n", min(dp[rank][0], dp[rank][1]));
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值