欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ZRDay6A. 萌新拆塔(三进制状压dp)

程序员文章站 2022-07-02 21:33:56
题意 Sol 这好像是我第一次接触三进制状压 首先,每次打完怪之后吃宝石不一定是最优的,因为有模仿怪的存在,可能你吃完宝石和他打就GG了。。 因此我们需要维护的状态有三个 0:没打 1:打了怪物 没吃宝石 2:打了怪物 吃了宝石 如果我们能知道打了那些怪,吃了那些宝石,那么此时的状态时确定的,预处理 ......

题意

ZRDay6A. 萌新拆塔(三进制状压dp)

ZRDay6A. 萌新拆塔(三进制状压dp)

 

sol

这好像是我第一次接触三进制状压

首先,每次打完怪之后吃宝石不一定是最优的,因为有模仿怪的存在,可能你吃完宝石和他打就gg了。。

因此我们需要维护的状态有三个

0:没打

1:打了怪物 没吃宝石

2:打了怪物 吃了宝石

如果我们能知道打了那些怪,吃了那些宝石,那么此时的状态时确定的,预处理出来

然后dp就行了

mdzz这题卡常数

/*
首先打完怪之后吃宝石不一定是最优的
因此我们需要枚举出每个怪物的状态
0:没打 
1:打了怪物 没吃宝石
2:打了怪物 吃了宝石
如果我们能知道打了那些怪,吃了那些宝石,那么此时的状态时确定的
 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<cmath>
//#define int long long 
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? eof : *p1++)
char buf[(1 << 22)], *p1 = buf, *p2 = buf;
#define ll long long 
using namespace std;
const int maxn = 2 * 1e6 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int t, n;
int lim, hp, a, f, m, mp[maxn], ia[maxn], if[maxn], im[maxn];//攻击 血量 防御 魔防 
ll f[maxn], po[16];
struct enemy {
    int h, a, d, s, ap, dp, mp, hp;
}a[15];
vector<int> v[16];
void init() {
    memset(f, 0, sizeof(f));
    hp = read(); a = read(); f = read(); m = read();
    n = read();    
    lim = po[n];
    for(int i = 1; i <= n; i++) {
        a[i].h = read();  a[i].a = read(); a[i].d = read(); a[i].s = read(); 
        a[i].ap = read(); a[i].dp = read(); a[i].mp = read(); a[i].hp = read();
    }
    int k = read();
    for(int i = 1; i <= n; i++) v[i].clear();
    for(int i = 1; i <= k; i++) {
        int u = read(), vv = read();
        v[vv].push_back(u);
    }
}
ll attack(int sta, int id) {
    ll now = f[sta], a = ia[sta], d = if[sta], m = im[sta];
    ll s = a[id].s, h = a[id].h, aa = a[id].a, d = a[id].d;
    if (s & 8) aa = a, d = d; // 模仿 
    if (s & 2) d = 0; // 无视防御 
    ll aa = max(0ll, a - d); // 勇士造成伤害 
    aa = max(0ll, aa - d) * (((s >> 2) & 1) + 1); // 怪物造成的攻击力,是否连击 
    if (aa == 0) return 0; 
    ll t1 = (h - 1) / aa + 1; // 需要打怪几次 
    ll t2 = (s & 1) ? (t1 * aa) : ((t1 - 1) * aa); // 怪造成的攻击力,是否有先攻 
    ll t3 = max(0ll, t2 - m); // 减去魔防 
    return max(0ll, now - t3);
}
void solve() {
    f[0] = hp;
    for(int sta = 0; sta < lim; sta++) {
        ia[sta] = a; if[sta] = f; im[sta] = m;
        for(int i = 1; i <= n; i++) 
            if(sta / po[i - 1] % 3 == 2)
                ia[sta] += a[i].ap, if[sta] += a[i].dp, im[sta] += a[i].mp;         
    }
    for(int sta = 0; sta < lim; sta++) {
        if(f[sta] == 0) continue;
        for(int i = 1; i <= n; i++) {
            if(sta / po[i - 1] % 3 == 0) {// not kill 
                bool flag = 0;
                for(int j = 0; j < v[i].size(); j++) 
                    if(sta / po[v[i][j] - 1] % 3 == 0) // not kiil
                        {flag = 1; break;}
                if(flag == 1) continue;
                ll nhp = attack(sta, i);
                if(nhp > 0) 
                    f[sta + po[i - 1]] = max(f[sta + po[i - 1]], nhp);
            } else if(sta / po[i - 1] % 3 == 1) {
                f[sta + po[i - 1]] = max(f[sta + po[i - 1]], f[sta] + a[i].hp);
            }
        }
    }
    printf("%lld\n", f[lim - 1] == 0 ? -1 : f[lim - 1]);
}
main() {
    po[0] = 1;
    for(int i = 1; i <= 15; i++) po[i] = 3 * po[i - 1];
    t = read();
    while(t--) {
        init();
        solve(); 
    }
    return 0;
}
/*
2 2 1
1 1
2 1 1
*/