[AH2017/HNOI2017]大佬(動態規劃 搜索)
阿新 • • 發佈:2019-04-09
swap getchar() ring truct ++ 規劃 最大 swa etc
/* 神仙yyb 理解題意可以發現 能夠對大佬造成的傷害只和你懟了多少天大佬有關, 而且顯然天數越多越好 那麽我們可以先通過預處理來找出我們最多能夠懟多少天大佬 然後我們發現最後我們能懟的血量狀態數是不多的??, 可以直接bfs弄一下 這樣的話我們處理出了所有的對(d, hp)表示可以使用d天打hp血量 然後暴力的話就是枚舉第一次懟了多少天, 第二次懟了多少天, 然後可以雙指針掃一下 這樣復雜度是 N * 狀態數的 假設我們找到的兩種情況分別是 (d1, hp1), (d2, hp2) 那麽需要滿足等式hp1 + hp2 <= C 和 hp1 + hp2 + (D - d1 - d2) >= C才可行 我們對於所有的狀態按照hp排序, 然後從大到小枚舉(hpi, di), 那麽我們要找到的就是hpj <= C - hpi 且 dj <= D - di 且 hpi + hpj + (D - di - dj) >= C 的點是否存在, 然後發現第二個限制沒有用 那麽我們就可以維護前綴的hpj - dj的最大值進行判斷了 只懟一次或者一次也不懟的情況可以直接判斷 我懷疑這個題目是個假題, 因為樣例中間一定會死?? */ #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<queue> #define ll long long #define M 110 #define mmp make_pair #include<set> using namespace std; int read() { int nm = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0'; return nm * f; } int n, m, maxx, tot, cnt; int f[M][M], a[M], w[M]; //int f[2][M][M], a[M], w[M]; int sum[10001000]; struct Note { int hp, d; bool operator < (const Note &b) const { return this->hp < b.hp; } }note[10001000]; struct Que { int ko, cost, l; }; const int inf = 100000000; set<ll>st; set<ll>::iterator it; bool find(ll x) { it = st.find(x); if(it != st.end()) return true; st.insert(x); return false; } ll ha(int hp, int d) { return 1ll * d * 10 * inf + hp; } void bfs() { queue<Que> q; q.push((Que) {1, 1, 0} ); while(!q.empty()) { Que now = q.front(); q.pop(); if(now.cost < tot) { q.push((Que){now.ko, now.cost + 1, now.l + 1}); if(now.l > 1 && 1ll * now.ko * now.l <= inf && !find(ha(now.ko * now.l, now.cost + 1))) { q.push((Que){now.ko * now.l, now.cost + 1, now.l}); note[++cnt] = (Note) {now.ko * now.l, now.cost + 1}; } } } } int workpre() { // int now = 1, last = 0; // f[now][maxx][0] = 1; // for(int k = 1; k <= n; k++) // { // swap(now, last); // memset(f[now], 0, sizeof(f[now])); // for(int i = a[k]; i <= maxx; i++) // { // for(int j = 0; j < k; j++) // { // if(f[last][i][j]) // { // f[now][i - a[k]][j + 1] = true, f[now][min(maxx, i - a[k] + w[k])][j] = true; // } // } // } // } // for(int i = n; i >= 0; i--) // { // for(int j = 0; j <= maxx; j++) // { // if(f[now][j][i]) return i; // } // } for(int i = 1; i <= n; i++) for(int j = a[i]; j <= maxx; j++) f[i][j - a[i]] = max(f[i - 1][j] + 1, f[i][j - a[i]]), f[i][min(j - a[i] + w[i], maxx)] = max(f[i - 1][j], f[i][min(j - a[i] + w[i], maxx)]); int ans = 0; for(int i = 1; i <= n; i++) for(int j = 1; j <= maxx; j++) ans = max(ans, f[i][j]); return ans; } int main() { n = read(), m = read(), maxx = read(); for(int i = 1; i <= n; i++) a[i] = read(); for(int i = 1; i <= n; i++) w[i] = read(); tot = workpre(); bfs(); sort(note + 1, note + cnt + 1); sum[0] = -inf; for(int i = 1; i <= cnt; i++) sum[i] = max(sum[i - 1], note[i].hp - note[i].d); while(m--) { int c = read(), flag = 0; if(c <= tot) flag = 1; else { int lst = 1; for(int i = cnt; i >= 1; i--) { while(lst <= cnt && note[i].hp + note[lst].hp <= c) lst++; if(note[i].hp <= c && tot - note[i].d >= c - note[i].hp) flag = true; if(sum[lst - 1] + note[i].hp - note[i].d >= c - tot) flag = true; } } cout << flag << "\n"; } return 0; }
[AH2017/HNOI2017]大佬(動態規劃 搜索)