[bzoj2096][Poi2010]Pilots(二分+单调队列)

来源:互联网 发布:所有香烟条形码数据库 编辑:程序博客网 时间:2024/05/17 03:53

题目:

我是超链接

题解:

这题目还真是简短啊,就是数据范围很不友善?
这个最大值二分无疑,如果暴力判断的话不就是mid*(n-mid+1)?再加上logn肯定boom!
nlogn可否?
我们可以二分一个最大值,用单调队列求出该长度的所有区间的最大值和最小值O(2n),然后判断maxx-minn是否<=k,只要有一组<=k答案就是可行的!

代码:

#include <cstdio>#include <iostream>#define N 3000005using namespace std;int n,k,a[N],maxx[N],minn[N],q[N];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0' || ch>'9'){if (ch=='-') f=-1; ch=getchar();}    while (ch<='9' && ch>='0') x=x*10+ch-'0',ch=getchar();    return x*f;}bool check(int mid){    int now=1,head=1,tail=0;    q[++tail]=1;maxx[1]=a[1];    for (int i=2;i<=n;i++)    {        while (q[head]<i-mid+1 && head<=tail) head++;//先把过时的t掉         while (a[q[tail]]<a[i] && head<=tail) tail--;//旧的小的t掉           q[++tail]=i;//构造单调递增队列         if (i-mid+1>0) maxx[i-mid+1]=a[q[head]];    }    head=1,tail=0;    q[++tail]=1;minn[1]=a[1];    for (int i=2;i<=n;i++)    {        while (q[head]<i-mid+1 && head<=tail) head++;        while (a[q[tail]]>a[i] && head<=tail) tail--;        q[++tail]=i;        if (i-mid+1>0) minn[i-mid+1]=a[q[head]];    }    for (int i=1;i<=n-mid+1;i++)      if (maxx[i]-minn[i]<=k) return 1;     return 0;}int main(){    int i;    k=read(); n=read();    for (i=1;i<=n;i++) a[i]=read();    int l=1,r=n,ans=1;    while (l<=r)    {        int mid=(l+r)>>1;        if (check(mid)) l=mid+1,ans=mid;        else r=mid-1;    }    printf("%d",ans);}

吐槽

luogu与bzoj不可调和的矛盾——
luogu上A了的程序到bzoj上WA了
bzoj上A了的程序到luogu上T了
???
那我就据理臆断一下:luogu上的人写了错解全都跑的飞快???
哎呀太不科学了不管了不管了

原创粉丝点击