题意太长
为了叙述方便,将题意中的$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 }