ZRDay6A. 萌新拆塔(三进制状压dp)
程序员文章站
2022-07-02 21:33:56
题意 Sol 这好像是我第一次接触三进制状压 首先,每次打完怪之后吃宝石不一定是最优的,因为有模仿怪的存在,可能你吃完宝石和他打就GG了。。 因此我们需要维护的状态有三个 0:没打 1:打了怪物 没吃宝石 2:打了怪物 吃了宝石 如果我们能知道打了那些怪,吃了那些宝石,那么此时的状态时确定的,预处理 ......
题意
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 */
上一篇: easyui 常用操作使用手册
下一篇: 机器人时代到来,人类去哪儿