1407D. Discrete Centrifugal Jumps(单调栈优化dp)

暂时只考虑 m a x ( a i , a j ) < m i n ( a i + 1 , . . . , a j 1 ) max(a_i,a_j)<min(a_{i+1},...,a_{j-1}) 这一种转移

说人话就是 [ i + 1 , j 1 ] [i+1,j-1] 的所有数都大于 a i a_i a j a_j

考虑维护一个单调递增的栈

p o s , a [ p o s ] > a j 在这个单增栈中的位置pos,如果a[pos]>a_j

[ p o s + 1 , j 1 ] a p o s 那么[pos+1,j-1]一定都是大于a_{pos}的

x 使 a x < = a p o s , a x a p o s 因为如果存在一个x使得a_x<=a_{pos},加入a_x会弹出a_{pos}

p o s 所以现在不就证明了位置pos合法嘛

p o s , 便 只需要在维护单增栈弹栈弹的就是那些pos,顺便转移一下就好了

[ i + 1 , j 1 ] a i a j 另一种情况就是要求[i+1,j-1]所有数都小于a_i和a_j

那同样维护一个单调递减的栈

a p o s < a j , [ p o s + 1 , j 1 ] a p o s 如果a_{pos}<a_j,那么说明[pos+1,j-1]都是小于a_{pos}的

同样转移即可

#include <bits/stdc++.h>
using namespace std;
const int maxn=8e5+10;
int n,a[maxn];
int down[maxn],up[maxn],top1,top2,f[maxn];
int main()
{
	cin >> n;
	for(int i=1;i<=n;i++)	cin >> a[i];
	down[++top1]=1,up[++top2]=1;
	f[0]=1e9;
	for(int i=2;i<=n;i++)
	{
		f[i]=f[i-1]+1;
		while( top2&&a[i]<a[up[top2]] )
			f[i]=min( f[i],f[up[top2--]]+1 );		
		while( top1&&a[i]>a[down[top1]] )
			f[i]=min( f[i],f[down[top1--]]+1 );
		f[i]=min( f[i],min( f[down[top1]],f[up[top2]] )+1 );//这里是第一个大于a[i]或小于a[i],可以转移 
		while( a[down[top1]]==a[i] )	top1--;//相等是不能转移的 
		while( a[up[top2]]==a[i] )	top2--;
		down[++top1]=i,up[++top2]=i;
	}
	cout << f[n];
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/108503278