/*
此题我先开始考虑的是每个数都不同,那么贪心就好。
然后由于有相同的那么我们考虑怎样消除,最后发现我贪心没法搞重换思路用了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;
}
bzoj2457
最新推荐文章于 2019-09-20 10:19:32 发布