【BZOJ】【1986】【USACO 2004 Dec】/【POJ】【2373】划区灌溉
DP/单调队列优化
首先不考虑奶牛的喜欢区间,dp方程当然是比较显然的:$ f[i]=min(f[k])+1,i-2*b \leq k \leq i-2*a $ 当然这里的$i$和$k$都是偶数啦~这个应该很好理解吧……每次喷灌的都是一个偶数长度的区间嘛……
那么加上奶牛的喜欢区间的话,只需这样:当$ i>cow[j].x $时,令$ i=cow[j].y , j++$ 也就是说中间的位置全部不考虑放喷灌器。
显然我们对于每个节点的 k 是可以用单调队列维护的!嗯看到这里的同学可以先自己试着去写写看啦~
如果过了样例不要着急,来试试我这组数据:
2 16
2 4
7 8
6 12
Trick:
每个奶牛的喜欢区间是一个【开区间】!分界点是可以被不同的喷灌器灌溉的(仔细看看样例的图)
一开始英文题面嘛……看了中文没细看英文……没看到还有【不合法情况输出-1】so sad……
每个f[i]不能刚算出来就弹队尾+进队尾,因为此时下一个位置为 i+2 ,可能会把能够转移到i+2的合法状态弹出去,而f[i]是不能转移到f[i+2]的!(因为有a的限制)所以会造成f[i+2]计算错误(当然f[l]就也有可能出错了。
事实上由于我们维护的队列是一个合法状态区间,所以目前不合法的状态不应该进队,而是应该在每次更新f[i]之前让 f[i-2*a] 进队,这样可以保证队列中所有节点都为合法状态。
然而!!刚才那种做法会有漏洞!因为我们会在遇到奶牛的喜欢区间的时候跳!过!去!所以一些合法状态就会来不及进队(比如我给的数据中的f[6]……所以在遇到奶牛区间的时候要将这个区间内所有合法的状态进队(当然要维护队列单调性了……需要弹队尾)
1 /************************************************************** 2 Problem: 1986 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:40 ms 7 Memory:9092 kb 8 ****************************************************************/ 9 10 //POJ 2373 11 #include<cmath> 12 #include<vector> 13 #include<cstdio> 14 #include<cstring> 15 #include<cstdlib> 16 #include<iostream> 17 #include<algorithm> 18 #define rep(i,n) for(int i=0;i<n;++i) 19 #define F(i,j,n) for(int i=j;i<=n;++i) 20 #define D(i,j,n) for(int i=j;i>=n;--i) 21 #define pb push_back 22 using namespace std; 23 int getint(){ 24 int v=0,sign=1; char ch=getchar(); 25 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 26 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 27 return v*=sign; 28 } 29 const int N=1e6+10,INF=~0u>>2; 30 typedef long long LL; 31 /******************tamplate*********************/ 32 //#define debug 33 struct Cow{ 34 int x,y; 35 Cow(){} 36 bool operator < (const Cow &b)const{ 37 return x<b.x || (x==b.x && y<b.y); 38 } 39 }cow[1010]; 40 int f[N],n,l,a,b; 41 int q[N]; 42 int main(){ 43 #ifndef ONLINE_JUDGE 44 freopen("2373.in","r",stdin); 45 // freopen("2373.out","w",stdout); 46 #endif 47 n=getint(); l=getint(); a=getint(); b=getint(); 48 F(i,1,n) cow[i].x=getint(),cow[i].y=getint(); 49 sort(cow+1,cow+n+1); 50 #ifdef debug 51 F(i,1,n) printf("%d %d\n",cow[i].x,cow[i].y); 52 cout <<endl; 53 #endif 54 int j=1; 55 F(i,1,l) f[i]=INF; 56 int st=0,ed=0; 57 f[0]=0; 58 q[ed++]=0; 59 for(int i=2;i<=l;i+=2){ 60 while(i>cow[j].x && j<=n){ 61 int last=i; 62 i=max(i,(cow[j].y+1)/2*2),j++; 63 for(int I=last;I<=i;I+=2) 64 if (f[I-2*a]!=INF){ 65 while(st<ed && f[q[ed-1]]>f[I-2*a]) ed--; 66 q[ed++]=I-2*a; 67 } 68 } 69 while(st<ed && q[st]<i-2*b) st++; 70 if(f[i-2*a]!=INF){ 71 while(st<ed && f[q[ed-1]]>f[i-2*a]) ed--; 72 q[ed++]=i-2*a; 73 } 74 if (st<ed && i-q[st]>=2*a) f[i]=f[q[st]]+1; 75 } 76 #ifdef debug 77 F(i,1,l) printf("%d ",f[i]==INF ? -1 : f[i]); 78 cout <<endl; 79 #endif 80 printf("%d\n",f[l]==INF ? -1 : f[l]); 81 return 0; 82 }