poj2373(单调队列优化dp)

匿名 (未验证) 提交于 2019-12-03 00:13:02

传送门

题意是每个洒水装置的半径范围为[A,B],每头奶牛有自己的一个区间[s,e],这个区间只能由一个洒水装置覆盖。

要求整个区间[1,L](L<=1e6)不重叠的被覆盖,最少要多少个洒水装置,洒水装置的范围不可以超过整体区间的范围。


我们用not_r[]来打个标记。

看到L的范围1e6,我们知道应该是使用O(n)的算法。

设f[i]表示处理到i这个位置需要的洒水装置个数。(i一定是右端点)。

f[i]=min(f[j])+1(A<=(i-j)/2<=B)

直接循环时间O(n^2)考虑优化。

我们发现对于点i,可以用的j一定是一段连续的区间,所以单队维护最小的f[j]。

因为一个j能不能被使用还要看它的位置是否满足限制,所以用队列id存一下下标。

因为i是右端点,所以在循环的时候,我们是偶数个的增加。

#include<cstdio> #include<iostream> #include<cstring> #define LL long long #define INF 2100000000 #define N 1000003 #define re register using namespace std; int read() {     int x=0,f=1;char s=getchar();     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}     return x*f; } void print(int x) {     if(x<0)x=-x,putchar('-');     if(x>9)print(x/10);     putchar(x%10+'0'); } int id[N],f[N],q[N],not_r[N]; int main() {     int n=read(),l=read();     int a=read(),b=read();     for(int i=1;i<=n;++i)     {         int s=read(),t=read();         for(int j=s+1;j<t;++j)           not_r[j]=1;     }     for(int i=1;i<=l;++i)f[i]=INF;     int h=1,t=0,head=1,tail=0;     id[++t]=0;     for(int i=2;i<=l;i+=2)//偶数个的加      {         if(not_r[i])continue;         while(h<=t&&(i-id[h])/2>=a)         {             while(head<=tail&&f[q[tail]]>=f[id[h]])tail--;             q[++tail]=id[h];//加入q里了,就可以移出id了              h++;         }         while(head<=tail&&(i-q[head])/2>b)head++;         if(head<=tail)         {             f[i]=f[q[head]]+1;             id[++t]=i;         }     }         if(f[l]!=INF)printf("%d\n",f[l]);     else printf("-1\n");      } /* */
View Code

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!