POJ1275 Cashier Employment 二分、差分约束

传送门

题意太长


为了叙述方便,将题意中的$0$点看作$1$点,$23$点看做$24$点

考虑二分答案(其实从小到大枚举也是可以的)

设$x_i$是我们选的雇员第$i$小时开始工作的人数,$s_i$是$x_i$的前缀和,又设$p_i$为可以在第$i$小时开始工作的人数,$q_i$表示第$i$小时需要的人数,$mid$为我们二分的答案

那么我们有

$$s_i-s_{i-8} geq q_i , 8 leq i leq 24$$

$$s_i - s_{i+16} geq q_i - mid , 1 leq i leq 7$$

$$s_{i - 1} - s_i geq -p_i$$

$$s_i - s_{i-1} geq 0$$(很容易漏掉)

$$s_{24}-s_{0} geq mid$$

最后一条边的原因是:注意到第二种边中我们强制了$s_{24} = mid$,但是实际跑出来的解有可能$s_{24} eq mid$,那么第二个式子就很有可能不成立。但是当$mid < s_{24}$时令$mid = s_{24}$时条件显然仍然成立,所以我们只需要让$s_{24} < mid$的时候强制让$s_{24} geq mid$才行。

直接差分约束求最长路就完了

差分约束有很多细节需要注意,掉了很多次坑qwq(比如每一次的queue都要清空)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 inline int read(){
 9     int a = 0;
10     bool f = 0;
11     char c = getchar();
12     while(c != EOF && !isdigit(c)){
13         if(c == '-')
14             f = 1;
15         c = getchar();
16     }
17     while(c != EOF && isdigit(c)){
18         a = (a << 3) + (a << 1) + (c ^ '0');
19         c = getchar();
20     }
21     return f ? -a : a;
22 }
23 
24 struct Edge{
25     int end , upEd , w;
26 }Ed[25*25];
27 int num[25] , x[25] , maxDis[25] , flo[25] , head[25] , cntEd , preHead[25] , preCnt;
28 queue < int > q;
29 bool inq[25];
30 
31 inline void addEd(int a , int b , int c){
32     Ed[++cntEd].end = b;
33     Ed[cntEd].upEd = head[a];
34     Ed[cntEd].w = c;
35     head[a] = cntEd;
36 }
37 
38 inline bool check(int mid){
39 while(!q.empty())q.pop();
40     memcpy(head , preHead , sizeof(preHead));
41     cntEd = preCnt;
42     for(int i = 1 ; i <= 8 ; i++)
43         addEd(i + 16 , i , num[i] - mid);
44     addEd(0 , 24 , mid);
45     memset(maxDis , -0x3f , sizeof(maxDis));
46     memset(inq , 0 , sizeof(inq));
47     memset(flo , 0 , sizeof(flo));
48     maxDis[0] = 0;
49     q.push(0);
50     while(!q.empty()){
51         int t = q.front();
52         q.pop();
53         inq[t] = 0;
54         for(int i = head[t] ; i ; i = Ed[i].upEd)
55             if(maxDis[Ed[i].end] < maxDis[t] + Ed[i].w){
56                 maxDis[Ed[i].end] = maxDis[t] + Ed[i].w;
57                 if((flo[Ed[i].end] = flo[t] + 1) >= 24)
58                     return false;
59                 if(!inq[Ed[i].end]){
60                     inq[Ed[i].end] = 1;
61                     q.push(Ed[i].end);
62                 }
63             }
64     }
65     return true;
66 }
67 
68 int main(){
69 #ifdef LG
70     freopen("1275.in" , "r" , stdin);
71 #endif
72     for(int T = read() ; T ; T--){
73         for(int i = 1 ; i <= 24 ; i++)
74             num[i] = read();
75         cntEd = 0;
76         memset(head , 0 , sizeof(head));
77         memset(x , 0 , sizeof(x));
78         int P = read() , L = 0 , R = P + 1;
79         for(int i = P ; i ; i--)
80             x[read() + 1]++;
81         for(int i = 0 ; i < 24 ; i++)
82             addEd(i , i + 1 , 0);
83         for(int i = 8 ; i <= 24 ; i++)
84             addEd(i - 8 , i , num[i]);
85         for(int i = 1 ; i <= 24 ; i++)
86             addEd(i , i - 1 , -x[i]);
87         memcpy(preHead , head , sizeof(head));
88         preCnt = cntEd;
89         while(L < R){
90             int mid = L + R >> 1;
91             check(mid) ? R = mid : L = mid + 1;
92         }
93         if(L > P)
94             puts("No Solution");
95         else
96             cout << L << endl;
97     }
98     return 0;
99 }
原文地址:https://www.cnblogs.com/Itst/p/9867664.html