题解:CF1647F Madoka and Laziness
更好的阅读体验
把一个序列拆成两个单峰子序列,每个子序列的峰值都是该子序列的最大值,因此原序列的最大值一定是其中一个子序列的峰值。那么问题就转化为有多少个位置可能成为另一个子序列的峰值。
设原序列最大值的位置为
假设我们确定了第二个序列峰值的位置
我们考虑一个贪心。因为我们已经确定了
具体地,我们设
这部分是好转移的,以
再考虑
到这里,因为我们刚才钦定了
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define N 500006
using namespace std;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
int n,a[N],f[2][N],g[2][N],ans;
void solve()
{
int maxn=-1e15,mxpos;
for(int i=1;i<=n;i++)
if(a[i]>maxn)maxn=a[i],mxpos=i;
memset(f[0],0x3f,sizeof(f[0])),f[0][0]=-1e15;
for(int i=1;i<=mxpos;i++)
{
if(a[i-1]<a[i])chkmin(f[0][i],f[0][i-1]);
if(f[0][i-1]<a[i])chkmin(f[0][i],a[i-1]);
}
memset(f[1],0x3f,sizeof(f[1])),f[1][n+1]=-1e15;
for(int i=n;i>=mxpos;i--)
{
if(a[i+1]<a[i])chkmin(f[1][i],f[1][i+1]);
if(f[1][i+1]<a[i])chkmin(f[1][i],a[i+1]);
}
memset(g[0],-0x3f,sizeof(g[0]));
memset(g[1],0x3f,sizeof(g[1])),g[1][mxpos]=f[0][mxpos];
for(int i=mxpos+1;i<=n;i++)
{
if(a[i-1]<a[i])chkmax(g[0][i],g[0][i-1]);
if(a[i-1]>a[i])chkmin(g[1][i],g[1][i-1]);
if(g[1][i-1]<a[i])chkmax(g[0][i],a[i-1]);
if(g[0][i-1]>a[i])chkmin(g[1][i],a[i-1]);
}
for(int i=mxpos+1;i<=n;i++)
if(g[0][i]>f[1][i])ans++;
}
main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
solve(),reverse(a+1,a+1+n),solve();
printf("%lld\n",ans);
return 0;
}