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)max(ai,aj)<min(ai+1,...,aj1)这一种转移

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

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

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

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

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

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

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

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

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

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

同 样 转 移 即 可 同样转移即可

#include 
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[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];
}

你可能感兴趣的:(div题解)