【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 }

时间: 2024-11-08 16:24:10

【BZOJ】【1986】【USACO 2004 Dec】/【POJ】【2373】划区灌溉的相关文章

BZOJ 1717 Usaco 2006 Dec 产奶模式

1717: [Usaco2006 Dec]Milk Patterns 产奶的模式 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1557  Solved: 847[Submit][Status][Discuss] Description 农夫John发现他的奶牛产奶的质量一直在变动.经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠.我们称之为一个"模式". John的牛奶按质量可以被赋予一个0到10000

BZOJ 1672 Usaco 2005 Dec Cleaning Shifts 清理牛棚 动态规划

题目大意:有一些牛,他们的牛舍需要被打扫.有N(N <= 10000)头牛愿意打扫,从时间S到时间T,需要花费一些金钱.问若要每时每刻都有牛在打扫,至少需要花多少钱. 思路:1w的数据量不算很大,再加上时限5s,就n^2动归来做. 将牛按时间段的开始排序. 设f[i]为若取第i头牛打扫,到这头牛结束的时间最小花费是多少. 则    f[i] = min(f[i],f[j] + cost[i])  (f[i].st <= f[j].ed + 1) 最后是初值和答案的问题.由于题目中说每时每刻都有

【USACO 2004 DEC】网络破坏Tree Cutting(DFS)

题目描述 约翰意识到贝茜建设网络花费了他巨额的经费,就把她解雇了.贝茜很愤怒,打算狠狠报 复.她打算破坏刚建成的约翰的网络. 约翰的网络是树形的,连接着N(1≤N≤10000)个牛棚.她打算切断某一个牛棚的电源,使和这个牛棚相连的所有电缆全部中断.之后,就会存在若干子网络.为保证破坏够大,每一个子网的牛棚数不得超过总牛棚数的一半,哪些牛棚值得破坏呢? 输入 第1行:一个整数N. 第2到N行:每行输入两个整数,表示一条电缆的两个端点. 输出 按从小到大的顺序,输出所有值得破坏的牛棚.如果没有一个值

BZOJ1986: [USACO2004 Dec] Dividing the Path 划区灌溉

L<=1000000的土地上用长度在2*A~2*B的线段覆盖所有点,且给定n<=1000个区间,每个区间上只允许有一条线段,求最少多少线段,无解-1. f[i]表示填前i个土地最少线段,f(i)=f(j)+1,2*A<=i-j<=2*B,用个单调队列就行.注意区间是左闭右开. 至于那些坏区间,如果某个状态在覆盖了该点的最远的右端点,那是合法的,否则一旦它被覆盖就是不合法状态. 为了处理这种情况,将区间按左端点排序,走到一个点时,若该点满足上面的情况,那就说明有一些区间的左端点<

bzoj 1986

1986: [USACO2004 Dec] Dividing the Path 划区灌溉 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 145  Solved: 89[Submit][Status] Description Farmer John's cows have discovered that the clover growing along the ridge of the hill in his field is particularly

bzoj:1675: [Usaco2005 Feb]Rigging the Bovine Election 竞选划区

Description It's election time. The farm is partitioned into a 5x5 grid of cow locations, each of which holds either a Holstein ('H') or Jersey ('J') cow. The Jerseys want to create a voting district of 7 contiguous (vertically or horizontally) cow l

USACO翻译:USACO 2014 DEC Silver三题

USACO 2014 DEC SILVER 一.题目概览 中文题目名称 回程 奶牛IDs 搬家 英文题目名称 piggyback cowids relocate 可执行文件名 piggyback cowids relocate 输入文件名 piggyback.in cowids.in relocate.in 输出文件名 piggyback.out cowids.out relocate.out 每个测试点时限 1秒 1秒 1秒 测试点数目 10 10 10 每个测试点分值 10 10 10 比较

USACO翻译:USACO 2013 DEC Silver三题

USACO 2013 DEC SILVER 一.题目概览 中文题目名称 挤奶调度 栅栏油漆 奶牛排队 英文题目名称 msched paint lineup 可执行文件名 msched paint lineup 输入文件名 msched.in paint.in lineup.in 输出文件名 msched.out paint.out lineup.out 每个测试点时限 1秒 1秒 1秒 测试点数目 10 10 10 每个测试点分值 10 10 10 比较方式 全文比较 全文比较 全文比较 二.运

POJ 2373 Dividing the Path(线段树+dp)

Dividing the Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3798   Accepted: 1363 Description Farmer John's cows have discovered that the clover growing along the ridge of the hill in his field is particularly good. To keep the clo