BZOJ 3100 排列——单调队列

来源:互联网 发布:好用的洗面奶知乎 编辑:程序博客网 时间:2024/05/29 10:54

3100

这道题很多网上的题解都是错的啊..

一部分题解对区间的要求:

1 不重复

2 和为k*(k+1)/2

3 最大值为k

很对啊。。但是貌似不重复这个东西用i-mx这样找区间很难判啊

——————(对错误题解的吐槽到此结束


依然是上面这几个条件

但是我们发现,只要满足1.3并且区间长度=k,则2必然满足

于是我们用枚举右端点,用bj[a[i]](表示a[i]上一次出现的位置)快速求出左端点,用单调队列维护区间最大值,判断R-L+1==MAX

完了。


注意弹出队列元素时计算答案


#include<iostream>#include<cstdio>#include<queue>#include<cmath>#include<algorithm>#include<cstring>#define For(i,j,k)for(ll i=j;i<=k;++i)#define Dow(i,j,k)for(ll i=k;i>=j;--i)#define maxm 10011#define maxn 511#define ll long longusing namespace std;inline ll read(){ll t=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c<='9'&&c>='0')t=t*10+c-48,c=getchar();return t*f;}int n,a[1001001],q[1001001],bj[1001001],ans,L;inline void check(int l,int r,int mx){if(mx>r)return;if(r-l+1==a[mx])ans=max(ans,a[mx]);}int main(){n=read();int l=1,r=0;For(i,1,n){L=max(L,bj[a[i]=read()]+1);while(l<=r&&q[l]<=bj[a[i]])check(q[l]+1,i-1,q[l+1]),++l;bj[a[i]]=i;while(l<=r&&a[q[r]]<=a[i])check(max(q[r-1]+1,L),i-1,q[r]),--r;q[++r]=i;q[r+1]=1e9;check(L,i,q[l]);}while(l+1<=r)check(q[l]+1,n,q[l+1]),l++;printf("%d\n",ans);}


原创粉丝点击