bzoj3126[Usaco2013 Open]Photo 单调队列+dp

来源:互联网 发布:酷q机器人php源码 编辑:程序博客网 时间:2024/06/03 18:41

又是久违的单队dp。。然而我并没有切出来,真是菜哭了。。
题意:给你一个n长度的数轴和m个区间,每个区间里有且仅有一个点,问能有多少个点

一开始还在想能不能乱搞,因为被包含的区间肯定是没用的,只有相交的区间才有用,问题是哪怕是相交也会有很多种奇葩的情况,感觉分类讨论应该不对。
然后线段树啊啥的都想过就是没想过dp。。
真是傻叉啊我。。
设f[i]表示做到i这个位置,必选i的最大方案数。
那么f[i]=f[j]+1,j是上一次选的位置。
那么我们可以发现j的选取肯定可以是一个区间。
怎么确定这个区间呢。
我们设这个区间为l[i],r[i].
由于每个读入的区间内必须只有一个点,所以包含这个点的区间都不能放,所以r[i]=i-1
由于每个读入的区间内必须要有一个点,所以不能有区间空着不放,所以l[i]=i左边的完整区间的最大左端点。
所以在读入每个区间l1,r1时我们就可以更新一下l,r
l[r1]=min(l1-1);
r[r1+1]=max(l1);
然后可以得出dp式f[i]={f[j],l[i]<=j<=r[i]}+1;
j的维护用单调队列。
//以后遇见区间问题还是想想单队dp。。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define inf 0x7f7f7f7fusing namespace std;const int N=5e5+5;int n,m;int cov[N],f[N];int l[N],r[N];int a[N];int q[N];int main(){    scanf("%d%d",&n,&m);    fo(i,1,n+1)r[i]=i-1;     fo(i,1,m)    {        int l1,r1;        scanf("%d%d",&l1,&r1);        r[r1]=min(r[r1],l1-1);        l[r1+1]=max(l[r1+1],l1);        //q[i].l=l,q[i].r=r;    }    fd(i,n,1)r[i]=min(r[i+1],r[i]);    fo(i,2,n+1)l[i]=max(l[i],l[i-1]);    int j=1;    int t=1,w=1;    q[1]=0;    fo(i,1,n+1)    {        while (j<=r[i]&&j<=n)        {            if (f[j]==-1)            {                j++;                continue;            }            while (f[j]>f[q[w]]&&t<=w)w--;            q[++w]=j;            j++;        }        while (q[t]<l[i]&&t<=w)t++;        if (t<=w)f[i]=f[q[t]]+(i!=n+1?1:0);        else f[i]=-1;     }    printf("%d\n",f[n+1]);}
阅读全文
0 0