有一个大佬,自信值为C C C ,你的自信值为m c \mathrm{mc} m c ,初始L = 0 , F = 1 L=0, F=1 L = 0 , F = 1
大佬每天会使你的自信值减少a i a_i a i ,你只要自信值非负,则每天可以选择以下操作之一:
让自己的自信值提高w i w_i w i
让大佬的自信值C C C 减一
让自己等级L L L 加一
让自己的嘲讽能力F ∗ = L F*=L F ∗ = L
对大佬造成
的伤害
,然后使
。该操作不能超过两次
多组询问
,对于每组询问回答能否恰好使得
,询问相互独立
Links Luogu P3724
LOJ 2021
Analysis 原问题可以拆成两个部分,求出在活着的前提下最多能进行其他操作的天数
剩下的部分由于状态数很少,可以Bfs
出所有状态,利用所求东西的单调性,two pointer
解决
Solution 首先肯定是尽量苟活,也就是花费最少的天数提高自信值
这个东西可以dp算一下,d p [ i ] [ j ] dp[i][j] d p [ i ] [ j ] 表示到第i i i 天,自信值为j j j 时,最多可以花费多少天进行提高自信值以外的操作
最后扫一遍就能求出最多能进行其他操作的天数M a x D a y MaxDay M a x D a y
接下来考虑3、4操作,发现又可以dp,不难注意到状态数很少这个事实,于是可以Bfs+Hash
求出所有状态
状态( f , d ) (f, d) ( f , d ) 表示用d d d 天可以产生f f f 的嘲讽能力
最后考虑5操作,不操作和操作一次的情况很好判断,下面讨论操作两次的情况:
假设两次的状态分别为( f 1 , d 1 ) , ( f 2 , d 2 ) (f_1, d_1),(f_2, d_2) ( f 1 , d 1 ) , ( f 2 , d 2 ) ,那么需要满足:
d 1 + d 2 ≤ M a x D a y f 1 + f 2 ≤ C f 1 + f 2 + ( M a x D a y − d 1 − d 2 ) ≥ C
\begin{aligned}
&d_1 + d_2 \le MaxDay\\\\
&f_1 + f_2 \le C\\\\
&f_1 + f_2 + (MaxDay - d_1 - d_2) \ge C
\end{aligned}
d 1 + d 2 ≤ M a x D a y f 1 + f 2 ≤ C f 1 + f 2 + ( M a x D a y − d 1 − d 2 ) ≥ C 显然第三个限制包含了第一个限制,于是可以只考虑后面两个限制,而最后一个限制可以化简为:
f 1 − d 1 + f 2 − d 2 ≥ C − M a x D a y
f_1 - d_1 + f_2 - d_2 \ge C - MaxDay
f 1 − d 1 + f 2 − d 2 ≥ C − M a x D a y 考虑按f f f 排序,用two pointer
扫出对于每个f i f_i f i 作为f 1 f_1 f 1 时,所对应f 2 f_2 f 2 的范围
由于此时f 1 , d 1 , C , M a x D a y f_1, d_1, C, MaxDay f 1 , d 1 , C , M a x D a y 都是确定的,所以只要考虑f 2 − d 2 f_2 - d_2 f 2 − d 2 的最大值,这个在指针扫的时候记录一下即可
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 #include <bits/stdc++.h> #define x first #define y second #define y1 Y1 #define y2 Y2 #define mp make_pair #define pb push_back using namespace std ;typedef long long LL;typedef pair <int , int > pii;template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0 ; }template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0 ; }template <typename T> inline T read () { T sum = 0 , fl = 1 ; char ch = getchar(); for (; !isdigit (ch); ch = getchar()) if (ch == '-' ) fl = -1 ; for (; isdigit (ch); ch = getchar()) sum = (sum << 3 ) + (sum << 1 ) + ch - '0' ; return sum * fl; } inline void proc_status () { ifstream t ("/proc/self/status" ) ; cerr << string (istreambuf_iterator <char > (t), istreambuf_iterator <char > ()) << endl ; } const int Maxn = 100 + 10 ;int N, M, MC, A[Maxn], W[Maxn], C[Maxn], MaxC;int Dp[Maxn][Maxn], MaxDay;inline void Pre_Dp () { for (int i = 1 ; i <= N; ++i) { for (int j = A[i]; j <= MC; ++j) { Chkmax(Dp[i][j - A[i]], Dp[i - 1 ][j] + 1 ); Chkmax(Dp[i][min(j - A[i] + W[i], MC)], Dp[i - 1 ][j]); } } for (int i = 1 ; i <= N; ++i) for (int j = 0 ; j <= MC; ++j) Chkmax(MaxDay, Dp[i][j]); } struct info { int d, f, l; };set <pii> S;pii State[(int )1e6 + 100 ]; int state_cnt;inline void Bfs () { static queue <info> Q; Q.push((info){1 , 1 , 0 }); while (!Q.empty()) { info x = Q.front(); Q.pop(); if (x.d == MaxDay) continue ; Q.push((info){x.d + 1 , x.f, x.l + 1 }); if (x.l > 1 && (LL)x.f * x.l <= MaxC && !S.count(mp(x.f * x.l, x.d + 1 ))) { Q.push((info){x.d + 1 , x.f * x.l, x.l}); S.insert(mp(x.f * x.l, x.d + 1 )), State[++state_cnt] = mp(x.f * x.l, x.d + 1 ); } } sort(State + 1 , State + state_cnt + 1 ); } inline void Solve () { Pre_Dp(); Bfs(); for (int pp = 1 ; pp <= M; ++pp) { if (MaxDay >= C[pp]) { puts ("1" ); continue ; } int j = 1 , Max = -0x3f3f3f3f , fl = 0 ; for (int i = state_cnt; i >= 1 ; --i) { while (j < state_cnt && State[i].x + State[j].x <= C[pp]) Chkmax(Max, State[j].x - State[j].y), ++j; if (State[i].x <= C[pp] && State[i].x - State[i].y >= C[pp] - MaxDay) {fl = 1 ; break ; } if (State[i].x - State[i].y + Max >= C[pp] - MaxDay) {fl = 1 ; break ; } } printf ("%d\n" , fl); } } inline void Input () { N = read<int >(), M = read<int >(), MC = read<int >(); for (int i = 1 ; i <= N; ++i) A[i] = read<int >(); for (int i = 1 ; i <= N; ++i) W[i] = read<int >(); for (int i = 1 ; i <= M; ++i) Chkmax(MaxC, C[i] = read<int >()); } int main () {#ifndef ONLINE_JUDGE freopen("A.in" , "r" , stdin ); freopen("A.out" , "w" , stdout ); #endif Input(); Solve(); return 0 ; }