【DP】Gym101623A Ascending Photo

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85696474

【题目】
原题地址
给定一个序列,问最少将序列切多少刀并重排后,序列单调不降。 n 1 0 6 n\leq 10^6

【解题思路】
这个 DP \text{DP} 十分有趣啊。
首先我们先把所有数离散化后都用挡板分开,现在问题就是去掉最多的挡板。观察到当存在连续序列 ( a , a + 1 , a + 2 ) (a,a+1,a+2) a + 1 a+1 在数组中不唯一时,去掉 ( a , a + 1 ) (a,a+1) 的挡板可能导致 ( a + 1 , a + 2 ) (a+1,a+2) 的挡板无法去除。

我们用 f i f_i 表示去除数值 ( 0 , 1 ) (0,1) ( i , i + 1 ) (i,i+1) 的所有可去除挡板数量。注意到 f f 的值和去除那一块可选挡板有关因此我们需要加一维,设 f i , j f_{i,j} 表示去除 ( i , i + 1 ) (i,i+1) 挡板时考虑位置 ( j , j + 1 ) (j,j+1)

即首先 i i j j 有条件 a j = i , a j + 1 = i + 1 a_j=i,a_{j+1}=i+1
f i , j = max ( f i 1 , j + [ j j ] ) f_{i,j}=\max(f_{i-1,j'}+[j不是j'产生的冲突位置])
这个条件等价于 j = j + 1 j=j'+1 a j a_j 不唯一。

那么对于一个 j j' ,最多产生一个冲突位置 j + 1 j'+1 (当a_{j’+1}唯一就不是冲突位置)。
对于一个 j j ,只可能是一个位置 j = j 1 j'=j-1 的冲突位置。

如果我们把 f i f_i 看作一张表,最后求的就是 f n f_n 的最大值。

观察转移方程,从f_i向f_{i+1}转移的时候,求 max \max 的是 f i f_i 这张表的所有元素,但其中有些元素加了 1 1 j j 不是 j j' 的冲突位置)。

所以,我们只需保存这张表最大的那些值就行了。具体来说我们只用保留最大值和次大值:
回顾条件,当我们保存了两个 f f 值最大的 j j' 对应的冲突位置时,那么求 f i , j f_{i,j} 就能一定找到一个不冲突的位置,然后累计加上 1 1

所以最终复杂度为 O ( n ) O(n)

【参考代码】

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int N=1e6+10;
int n,sz,b[N];
vector<int>a,pos[N];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
#endif
	n=read();
	for(int i=1;i<=n;++i)
	{
		int x=read();
		if(a.empty() || a.back()!=x) a.pb(x);
	}
	n=(int)a.size();
	for(int i=0;i<n;++i) b[i]=a[i];
	sort(b,b+n);sz=unique(b,b+n)-b;
	for(int i=0;i<n;++i) a[i]=lower_bound(b,b+sz,a[i])-b,pos[a[i]].pb(i);
	pii s1=mkp(0,n),s2=mkp(0,n);
	for(int i=0;i<sz-1;++i)
	{
		pii t1=s1,t2=s2;
		for(int j=0;j<(int)pos[i].size();++j)
		{
			int p=pos[i][j];
			if(p==n-1 || a[p]+1!=a[p+1]) continue;
			pii s=mkp(0,n);
			if(p^s1.se) s=s1; else s=s2;
			++s.fi;s.se=p+1;
			if(pos[i+1].size()==1) s.se=n;
			if(s>t1) t2=t1,t1=s;
			else if(s>t2) t2=s;
		}
		s1=t1;s2=t2;
	}
	printf("%d",n-s1.fi-1);

	return 0;
}

【总结】
层层递进的思想,挺难想的吧qwq。

扫描二维码关注公众号,回复: 4786120 查看本文章

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/85696474