hdu1529 Cashier Employment[差分约束+二分答案]

这题是一个类似于区间选点,但是有一些不等式有三个未知量参与的情况。


依题意,套路性的,将小时数向右平移1个单位后,设$f_i$为前$i$小时工作的人数最少是多少,$f_{24}$即为所求。设$c_i$为第$i$小时可选人数,$lim_i$为要求人数下限。

  • $0le f_i-f_{i-1}le c_i$,保证合法
  • $ige 8$时,$f_i-f_{i-8}ge lim_i$
  • $i<8$时,由于环形,$f_i+(f_{24}-f_{i+16})ge lim_i$,但这个不好处理,因为这不是一个二元关系,有第三个未知数参与。不过分析可知这些不等式中参与的第三个量是同一个,那么我们可以暴力枚举这个$f_{24}$,然后化为二元,再建图看合不合法。
  • 使用上一条的方法时,注意限制$f_{24}-f_0=枚举的数$

事实上,答案满足可二分性,于是改为二分答案,跑正环检验即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<queue>
 7 #define dbg(x) cerr << #x << " = " << x <<endl
 8 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
 9 using namespace std;
10 typedef long long ll;
11 typedef double db;
12 typedef pair<int,int> pii;
13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
15 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
16 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
17 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
18 template<typename T>inline T read(T&x){
19     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
20     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
21 }
22 const int N=1000,INF=0x3f3f3f3f;
23 struct thxorz{int to,nxt,w;}G[N];
24 int Head[26],tot;
25 int cnt[26],lim[26];
26 int T,n,L,R;
27 inline void Addedge(int x,int y,int z){G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot,G[tot].w=z;}
28 int dis[26],inq[26],rel[26];
29 #define y G[j].to
30 inline bool spfa(){
31     queue<int> q;
32     for(register int i=0;i<=24;++i)q.push(i),dis[i]=0,inq[i]=1,rel[i]=0;
33     while(!q.empty()){
34         int x=q.front();q.pop();
35         inq[x]=0;//dbg(x);
36         for(register int j=Head[x];j;j=G[j].nxt)if(MAX(dis[y],dis[x]+G[j].w)){
37             rel[y]=rel[x]+1;if(rel[y]>=25)return 0;//dbg(y);
38             if(!inq[y])inq[y]=1,q.push(y);
39         }
40     }
41     return 1;
42 }
43 #undef y
44 inline bool check(int mid){
45     memset(Head,0,sizeof Head),tot=0;
46     for(register int i=1;i<=24;++i)Addedge(i-1,i,0),Addedge(i,i-1,-cnt[i]);
47     for(register int i=8;i<=24;++i)Addedge(i-8,i,lim[i]);
48     for(register int i=1;i<8;++i)Addedge(i+16,i,lim[i]-mid);
49     Addedge(0,24,mid),Addedge(24,0,-mid);
50     return spfa(); 
51 }
52 
53 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
54     read(T);while(T--){
55         for(register int i=1;i<=24;++i)read(lim[i]);
56         memset(cnt,0,sizeof cnt);
57         read(n);for(register int i=1,x;i<=n;++i)read(x),cnt[x+1]++;
58         L=0,R=n+1;//dbg(check(1)),dbg(check(2)),dbg(check(3)),dbg(check(4)),dbg(check(5));
59         while(L<R){
60             int mid=L+R>>1;
61             if(check(mid))R=mid;
62             else L=mid+1;
63         }
64         if(L<=n)printf("%d
",L);
65         else puts("No Solution");
66     }
67     return 0;
68 }
View Code

一道弱智小题耗我半小时。。

RE记录:差分约束题建边老是容易在Addedge处写倒掉。注意本题$n$的意味,不要混淆成点数。

总结:第三元参入不等式,二分答案检验。

原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11646780.html