[HNOI2017] 大佬
阿新 • • 發佈:2018-12-02
Description
Solution
題目面長度堪比《離騷》,不過也是道巧妙題
這一題操作很多,混在一起不好考慮,那麼將他們分類進行處理。
總的來說,操作分為回覆和攻擊, 其中攻擊又有兩種型別,每種型別又互不干擾,所以可以拆開處理。 可以發現大佬攻擊和自己回覆的值是一定的,而大佬不會回覆,所以兩個操作互不影響,所以分開求解。我們只要求出一個時間長度, 並且在這個長度內擊敗大佬即可。
那麼設\(dp[i][j]\) 表示到第i天,自信值還有j的情況下最多有\(dp[i][j]\)天不回覆用來攻擊的最大值.
接下來考慮攻擊, 考慮這樣一個狀態\((i,j)\)
那麼有:
\[ I_1 + I_2 \leq HP ~ \&\& ~ I_1 + I_2 + (D - J_1 - J_2) \geq C \]
然後排序之後,TwoPointer掃一下就可以了。
Inspiration
在題目的要求/操作/限制條件很多的時候,我們可以分類進行處理。
這一題的模型其實就是用01揹包表示出一個特定的值,但是因為第三種物品太多,前兩種物品很少。所以我們可以列舉前兩種,計算第三種。 (gsa)而列舉可以採用twopointer,因為前兩種物品有單調性。(gsa)
Code
#include<bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i) #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i) #define clar(a, b) memset((a), (b), sizeof(a)) #define debug(...) fprintf(stderr, __VA_ARGS__) typedef long long LL; typedef long double LD; int read() { char ch = getchar(); int x = 0, flag = 1; for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1; for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; return x * flag; } void write(int x) { if (x < 0) putchar('-'), x = -x; if (x >= 10) write(x / 10); putchar(x % 10 + 48); } const int Maxn = 109, Maxm = 29, Maxmc = 109; const int HashSize = 1000009; int n, m, mc, a[Maxn], w[Maxn], C[Maxn]; int dp[Maxn][Maxmc]; struct node { int tims, damage, level; int operator < (const node nothaer) const { return damage < nothaer.damage || damage == nothaer.damage && tims < nothaer.tims; } int operator == (const node nothaer) const { return tims == nothaer.tims && damage == nothaer.damage; } }; struct HASH { int head[HashSize], nxt[HashSize * 20], size; node to[HashSize]; HASH() { clar(head, -1); } void insert(node val) { int res = (val.level * 817ll % HashSize + val.damage * 1926ll % HashSize + val.tims * 19260817ll % HashSize) % HashSize; for (int i = head[res]; ~i; i = nxt[i]) if (to[i] == val) return ; to[++size] = val; nxt[size] = head[res]; head[res] = size; } int exist(node val) { int res = (val.level * 817ll % HashSize + val.damage * 1926ll % HashSize + val.tims * 19260817ll % HashSize) % HashSize; for (int i = head[res]; ~i; i = nxt[i]) if (to[i] == val) return 1; return 0; } }tab; void init() { n = read(), m = read(), mc = read(); rep (i, 1, n) a[i] = read(); rep (i, 1, n) w[i] = read(); rep (i, 1, m) C[i] = read(); } int Limit = 0, limitDam, LZ; queue <node> que; vector <node> Fkq; void BFS() { que.push((node){1, 1, 0}); tab.insert((node){1, 1, 0}); Fkq.push_back((node){1, 1, 0}); while (!que.empty()) { node u = que.front(); que.pop(); if (u.tims < Limit) { node New = (node){u.tims + 1, u.damage, u.level + 1}; if (!tab.exist(New)) tab.insert(New), que.push(New); New = (node){u.tims + 1, u.damage * u.level, u.level}; if (1ll * u.level * u.damage <= 1ll * LZ && !tab.exist(New) && u.level > 1) tab.insert(New), que.push(New), Fkq.push_back(New); } } } void solve() { clar(dp, -1), dp[0][mc] = 0; rep (i, 0, n) rep (j, 0, mc) if(~dp[i][j]) { if (j >= a[i + 1]) dp[i + 1][min(j - a[i + 1] + w[i + 1], mc)] = max(dp[i + 1][min(j - a[i + 1] + w[i + 1], mc)], dp[i][j]); if (j >= a[i + 1]) dp[i + 1][j - a[i + 1]] = max(dp[i + 1][j - a[i + 1]], dp[i][j] + 1); } rep (i, 1, n) rep (j, 0, mc) limitDam = Limit = max(Limit, dp[i][j]); rep (i, 1, n) LZ = max(LZ, C[i]); BFS(); sort(Fkq.begin(), Fkq.end()); rep (i, 1, m) { int Flag = 0, Max = -0x3f3f3f3f, leftPoint = 0; if (C[i] <= limitDam) { puts("1"); continue; } drep (j, Fkq.size() - 1, 0) { for (; leftPoint < (int)Fkq.size() - 1 && Fkq[leftPoint].damage + Fkq[j].damage <= C[i]; ++leftPoint) Max = max(Max, Fkq[leftPoint].damage - Fkq[leftPoint].tims); if (Max + Fkq[j].damage - Fkq[j].tims >= C[i] - limitDam) { Flag = 1; break; } if (C[i] >= Fkq[j].damage && Fkq[j].damage + limitDam - Fkq[j].tims >= C[i]) { Flag = 1; break; } } puts(Flag ? "1" : "0"); } } int main() { init(); solve(); #ifdef Qrsikno debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC); #endif return 0; }