https://codeforces.com/contest/1407/problem/D
mdA题没做出来,吧D过了以后一看cf predictor竟然还能上分,刷牙的时候想着不会fst哪题吧?回来一看这题fst了我透,日常优化常数把人剪没了。
可以发现,我们如果要从i跳到j,那么假设我们当前在i,如果a[i+1]>a[i],那么只能按照一个严格下降子序列转移,否则则是按照一个严格上升子序列转移,
所以用树状数组预处理出每个位置右边离它最近的比他大的nxtup[i]和比他小的nxtd[i],然后一直向右判断能否转移就行了,如果还没更新过或者不如当前转移优就能转移。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,cnt,tot,cas,ans;
int a[maxl],dp[maxl],num[maxl];
int b[maxl],nxtup[maxl],nxtd[maxl];
char s[maxl];
inline void upd(int i,int x)
{
while(i<=tot)
{
b[i]=min(x,b[i]);
i+=i&-i;
}
}
inline int qry(int i)
{
int ret=n+1;
while(i)
{
ret=min(ret,b[i]);
i-=i&-i;
}
return ret;
}
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),num[i]=a[i];
sort(num+1,num+1+n);
tot=unique(num+1,num+1+n)-num-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(num+1,num+1+tot,a[i])-num;
for(int i=0;i<=tot;i++)
b[i]=n+1;
int c;
for(int i=n;i>=1;i--)
{
c=a[i];
nxtd[i]=qry(c-1);
upd(c,i);
}
for(int i=0;i<=tot;i++)
b[i]=n+1;
for(int i=n;i>=1;i--)
{
c=tot-a[i]+1;
nxtup[i]=qry(c-1);
upd(c,i);
}
}
inline void mainwork()
{
dp[1]=0;int now,last;
for(int i=2;i<=n;i++)
dp[i]=n-1;
for(int i=1;i<=n-1;i++)
{
dp[i+1]=min(dp[i+1],dp[i]+1);
if(a[i+1]>a[i])
{
now=i+1;
while(nxtd[now]<=n)
{
last=now;now=nxtd[now];
if(dp[now]<=dp[i]+1 || a[last]<=a[i])
break;
dp[now]=min(dp[now],dp[i]+1);
}
}
if(a[i+1]<a[i])
{
now=i+1;
while(nxtup[now]<=n)
{
last=now;now=nxtup[now];
if(dp[now]<=dp[i]+1 || a[last]>=a[i])
break;
dp[now]=min(dp[now],dp[i]+1);
}
}
}
}
inline void print()
{
printf("%d\n",dp[n]);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}