正解:dp+bfs
解题报告:
这题看起来很复杂的样子其实真的很复杂
但是仔细看一下题目,会发现其实操作只有两个目的嘛,一个是保证自己不死,一个是让对手减血
而且保证自己不死只有一种操作
而且这种操作和其他东西都麻油关系,不管多少血量,不管你前面的操作是哪些,反正加的血量是一样的
所以考虑把这两个分开来思考
首先求血量
考虑到要留尽量多的时间让对手减血,而对于攻击对手这个事儿来说,无论哪天攻击造成的伤害都是相等的,对于具体日期麻油要求,看到这样子就要想到dp了嘛(具体日期无影响鸭QAQ
所以设状态f[i][j]:第i天血量为j,最多不用刷题(也就是涨血)几天
转移很简单嘛,普通背包
然后取dp中的max,也就是最多能用来攻击对手的时间D
接下来考虑攻击对手
首先肯定是要么345组合拳要么1,相当于只有两种
设用345的两次方案分别是(d1,h1)(d2,h2),表示积累d天伤害为h
再设对手的血量为HP
然后如果要战胜对手,首先不能血量为负,所以h1+h2<=HP
又要活下去,所以HP-h1-h2<=D-d1-d2
然后上面是攻击两次嘛,如果攻击一次相当于有一组=(0,0)就好,不攻击就是两组都=(0,0)就好
然后就做完了
然后说下具体做法
首先就枚举状态昂,bfs枚举出所有可能的状态,然后把这些状态按h为第一关键字d为第二关键字地排序
然后对h从大到小地枚举第一次攻击
第二次攻击,可以先对上面的式子移项,得D>=HP-h1-h2+d1+d2
又h1d1其实是已知式,所以就是D>=T+d2-h2
如果有合法方案就说明对手会死嘛,所以要努力让它合法,就是说要努力保证d2-h2合法
但还有一个要求昂,就h1+h2<=HP
所以就在满足h1+h2<=HP的条件下,增大h2(即指针向后扫),每次取(-h2+d2)min,然后比较,O(状态数)扫过去就好
然后另外有个小细节就是这里有个手写hash
但是很简单,简单的hash思想+链式前向星思想就好,不想多说,自己看代码就好QAQ
#include<bits/stdc++.h> using namespace std; #define il inline #define rg register #define gc getchar() #define mp make_pair #define fr first #define sc second #define int long long #define rp(i,x,y) for(rg int i=x;i<=y;++i) #define my(i,x,y) for(rg int i=x;i>=y;--i) #define e(i,x) for(rg int i=head[x];i;i=edge[i].nxt) const int N=200+10,M=2000000+10000,mod=10162003; int n,m,mc,a[N],w[N],c[N],f[N][N],dmx,mxc,zt_cnt; pair<int,int>zt[M]; struct node{int f,l,d;}; struct hsh { struct ed{int x,y,nxt;}edge[M]; int head[mod+100],cnt; void push(int x,int y){int pos=(1ll*x*101+y)%mod;edge[++cnt]=(ed){x,y,head[pos]};head[pos]=cnt;} bool query(int x,int y){int pos=(1ll*x*101+y)%mod;e(i,pos)if(edge[i].x==x&&edge[i].y==y)return true;return false;} }mapp; il int read() { char ch=gc;int x=0;bool y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il void dp() { rp(i,1,n) rp(j,a[i],mc) { f[i][j-a[i]]=max(f[i-1][j]+1,f[i][j-a[i]]); f[i][min(j-a[i]+w[i],mc)]=max(f[i-1][j],f[i][min(j-a[i]+w[i],mc)]); } rp(i,1,n)rp(j,0,mc)dmx=max(dmx,f[i][j]); } il void bfs() { queue<node>Q;Q.push((node){1,0,1}); while(!Q.empty()) { node tmp=Q.front();Q.pop(); if(tmp.d==dmx)continue; Q.push((node){tmp.f,tmp.l+1,tmp.d+1}); if(tmp.l>1 && 1ll*tmp.f*tmp.l<=mxc && !mapp.query(tmp.f*tmp.l,tmp.d+1)) { Q.push((node){1ll*tmp.f*tmp.l,tmp.l,tmp.d+1}); zt[++zt_cnt]=mp(1ll*tmp.f*tmp.l,tmp.d+1); mapp.push(tmp.f*tmp.l,tmp.d+1); } } } il void wk(int hp) { if(hp<=dmx)return void(printf("1\n")); int mn=1e9;int k=1; my(j,zt_cnt,1) { while(k<zt_cnt && zt[k].fr+zt[j].fr<=hp)mn=min(mn,zt[k].sc-zt[k].fr),++k; if(mn+hp-zt[j].fr+zt[j].sc<=dmx)return void(printf("1\n")); if(zt[j].fr<=hp && hp-zt[j].fr<=dmx-zt[j].sc)return void(printf("1\n")); } printf("0\n"); } main() { // freopen("dl.in","r",stdin);freopen("dl.out","w",stdout); n=read();m=read();mc=read();rp(i,1,n)a[i]=read();rp(i,1,n)w[i]=read();rp(i,1,m)mxc=max(mxc,c[i]=read()); dp();bfs();sort(zt+1,zt+1+zt_cnt);rp(i,1,m)wk(c[i]); return 0; }