1. 程式人生 > >BZOJ4828 AHOI/HNOI2017大佬(動態規劃+bfs)

BZOJ4828 AHOI/HNOI2017大佬(動態規劃+bfs)

math sub pre per 級別 include name map esp

  註意到懟大佬的操作至多只能進行兩次。我們逐步簡化問題。

  首先令f[i][j]表示第i天結束後自信值為j時至多有多少天可以進行非防禦操作(即恢復自信值之外的操作)。這個dp非常顯然。由於最終只需要保證存活,那麽取f中的最大值即可(可以在第n天之前使大佬自信值為0而結束),之後就不用再管自己的自信值。復雜度是O(n·mc),數據範圍遠遠沒有開滿,可能是怕提示做法吧。

  現在知道了有多少天可以用來攻擊(當然可以有些天劃水)。對於攻擊操作,哪一天進行是沒有區別的。那麽先不考慮還嘴操作。

  只剩下懟大佬的操作了。先看一次。雖然值域很大,操作方案數也是指數級別,但發現總共能打出來的在值域範圍內的傷害種類數在可以接受的範圍內。具體有多少我也不知道,總之我們可以暴搜剪剪枝map判個重(傷害和等級都相等),把所有可行傷害算出來。

  於是知道了用x天懟大佬可以造成的所有可行傷害。最多可以懟兩次,那麽給兩次懟操作分配天數,當然還有還嘴操作。

  假設總共n天,給兩次懟操作分配的天數分別為d1,d2,造成的傷害分別為w1,w2。如果能懟死大佬,則其滿足w1+w2<=q<=w1+w2+n-(d1+d2)。這樣不用考慮n的總天數限制。如果枚舉d1和w1,由前一個式子,隨著w1減小,滿足條件的最大的w2會增大。而由後一個式子,顯然應讓w2-d2盡量大。於是我們按照w排序,從大到小枚舉w1,並記錄w2-d2的最大值就可以了。

#include<iostream> 
#include<cstdio>
#include
<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3
)+(c^48),c=getchar(); return x*f; } #define N 110 #define inf 100000001 int n,m,Q,a[N],w[N],f[N][N],head,tail; map<long long,bool> g; struct data { int d,l,w; bool operator <(const data&a) const { return w<a.w; } }q[10000010]; long long calc(int x,int y){return 1ll*(n+1)*x+y;} void bfs() { q[tail=1]=(data){1,0,1};g[calc(1,0)]=1; do { head++;if (q[head].d==n) break; if (q[head].l>1&&1ll*q[head].w*q[head].l<inf&&!g[calc(q[head].w*q[head].l,q[head].l)]) g[calc(q[head].w*q[head].l,q[head].l)]=1,q[++tail]=(data){q[head].d+1,q[head].l,q[head].w*q[head].l}; if (1ll*q[head].w*(q[head].l+1)<inf&&!g[calc(q[head].w,q[head].l+1)]) g[calc(q[head].w,q[head].l+1)]=1,q[++tail]=(data){q[head].d+1,q[head].l+1,q[head].w}; }while (head<tail); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4828.in","r",stdin); freopen("bzoj4828.out","w",stdout); const char LL[]="%I64d"; #else const char LL[]="%lld"; #endif n=read(),Q=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=n;i++) w[i]=read(); memset(f,200,sizeof(f)); f[0][m]=0; for (int i=0;i<n;i++) for (int j=a[i+1];j<=m;j++) { f[i+1][min(m,j-a[i+1]+w[i+1])]=max(f[i+1][min(m,j-a[i+1]+w[i+1])],f[i][j]); f[i+1][j-a[i+1]]=max(f[i+1][j-a[i+1]],f[i][j]+1); } int v=0; for (int i=1;i<=n;i++) for (int j=0;j<=m;j++) v=max(v,f[i][j]); n=v; bfs(); sort(q+1,q+tail+1); q[0].d=q[0].l=q[0].w=0; while (Q--) { int x=read(),mx=-inf,p=-1; int flag=0; for (int j=tail;j>=1;j--) { while (p<tail&&q[p+1].w+q[j].w<=x) p++,mx=max(mx,q[p].w-q[p].d); if (q[j].w-q[j].d+mx+n>=x) {flag=1;break;} } cout<<flag<<endl; } return 0; }

BZOJ4828 AHOI/HNOI2017大佬(動態規劃+bfs)