LOJ传送门
每天的操作有很多种,但是实际上可以分为两大类。
第一类只与自己的自信值有关:刷水题/被大佬嘲讽。
第二类与大佬的自信值有关:L+=1、F乘等于L、还嘴、怼大佬
那么对于第一类,我们只要保证把大佬怼死前自信值非负就行了。而要保证自信值非负可以通过DP来求最多留出多少天来进行第二类操作。
假设求出来最多留出 D D D天来搞事情,问题就转化为一共只有 D D D天,每天可以L+=1、F乘等于L、还嘴、怼大佬。
然后可以通过暴力 B F S BFS BFS求出花了 d d d天能够怼掉大佬 f f f点自信值的 ( d , f ) (d,f) (d,f)数对,搜索的时候需要减枝( F F F超过最大的 C i C_i Ci就不继续了)。
求出来后按 f f f为第一关键字, d d d为第二关键字排序。
由于最多可以怼两次,怼一次或者不怼很显然。怼两次要求的就是是否存在 ( d 1 , f 1 ) , ( d 2 , f 2 ) (d1,f1),(d2,f2) (d1,f1),(d2,f2)满足 f 1 + f 2 ≤ C f1+f2\le C f1+f2≤C且 f 1 + f 2 + ( D − d 1 − d 2 ) ≥ C f1+f2+(D-d1-d2)\ge C f1+f2+(D−d1−d2)≥C。
我们从后往前枚举 i i i,设指针 j j j满足 f i + f j ≤ C f_i+f_j\le C fi+fj≤C且最大。那么固定 i i i的话, f 1 , D , d 1 , C f1,D,d1,C f1,D,d1,C都是定值,此时只需要求 f 2 − d 2 f2-d2 f2−d2的最大值就行了。直接存一下就行了。由于显然的单调性, j j j的位置一定是递增的。所以直接用一个变量存 j j j就行了。
#include
using namespace std;
typedef pair<int,int> pii;
typedef long long LL;
const int MAXN = 105;
const int MAXM = 25;
int n, m, mc, D, a[MAXN], w[MAXN], C[MAXM], mxc;
int f[MAXN][MAXN];
int predp() {
f[0][mc] = 0;
for(int i = 1; i <= n; ++i)
for(int j = a[i]; j <= mc; ++j) {
f[i][j-a[i]] = max(f[i][j-a[i]], f[i-1][j]+1);
f[i][min(j-a[i]+w[i],mc)] = max(f[i][min(j-a[i]+w[i],mc)], f[i-1][j]);
}
int re = 0;
for(int i = 1; i <= n; ++i) //注意这里不能只求f[n][i](i=1...mc)的最大值,因为可以没到第n天就把大佬怼死了
for(int j = 0; j <= mc; ++j)
re = max(re, f[i][j]);
return re;
}
struct node {
int x; pii y;
};
queue<node>myq;
map<pii, bool>vis;
pii val[2000005];
int cnt;
void BFS() {
myq.push((node){ 1, pii(1, 0) });
while(!myq.empty()) {
int d = myq.front().x, F = myq.front().y.first, L = myq.front().y.second; myq.pop();
if(d >= D) break;
myq.push((node){ d+1, pii(F, L+1) });
if(L > 1 && 1ll*F*L <= mxc && !vis.count(pii(F*L, d+1))) {
//这里判重我写的map 结果loj过了 luogu上过不了,必须手写hash表才能过
myq.push((node){ d+1, pii(F*L, L) });
vis[pii(F*L, d+1)] = 1;
val[++cnt] = pii(F*L, d+1);
}
}
}
int main () {
scanf("%d%d%d", &n, &m, &mc);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 1; i <= n; ++i) scanf("%d", &w[i]);
for(int i = 1; i <= m; ++i) scanf("%d", &C[i]), mxc = max(mxc, C[i]);
D = predp(); BFS(); sort(val + 1, val + cnt + 1);
for(int i = 1; i <= m; ++i) {
if(C[i] <= D) { puts("1"); continue; } //不怼
bool flg = 0; int mx = -0x3f3f3f3f;
for(int j = cnt, k = 1; j >= 1; --j) { //固定j 移动k
while(k <= cnt && val[k].first + val[j].first <= C[i]) {
mx = max(mx, val[k].first-val[k].second);
++k;
}
if(val[j].first-val[j].second+D+mx >= C[i]) { flg = 1; break; } //怼两次
if(val[j].first <= C[i] && val[j].first+D-val[j].second >= C[i]) { flg = 1; break; } //怼一次
}
printf("%d\n", flg);
}
}