[JSOI2008]魔獸地圖
阿新 • • 發佈:2018-07-23
手動 cos scanf 技術 std gist utc reg 以及
樹上背包
題目傳送門
首先,有沒有哪位dalao 願意告訴我為什麽合成高級裝備不需要附加金幣,,
好吧,這個不重要
明確表示裝備合成路線可以用一棵樹來表示。一顆?傻乎乎的在下之前每次就只dp一棵樹,不出意外的WA了,,在看幾遍,好嘛,好像是個森林啊(淚奔)
最容易想到的dp[x][i][j]是第x件買了i個,花了j元的最高力量。但是,,這樣好像就成為不可做題了(歡迎各路dalao打臉,反正不是我說的[手動滑稽](偷偷扔出FYJ擋槍)),那麽換一種思路,還是dp[x][i][j],但表示的是第x件裝備,用i件合成上級裝備(即至少買了i件),花費j元的力量。如果i是基礎裝備,轉移方程就直接出來了:d[x][i][j*cost[x]]=power[x]*(j-i)。
如果是高級裝備呢?
那就枚舉它買多少件,以及它的子裝備買多少件,直接暴力轉移,n^2*times^2。看看時限,3s,完全不方
在下代碼比較醜,求各位不要介意
#include<bits/stdc++.h> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<deque> #include<list> #include<set> #include<vector> #include<iostream> #define ll int #define re register #define inf 0x3f3f3f3f #define inl inline #define sqr(x) (x*x) //#define eps 1e-8 #define debug printf("debug\n"); //#pragma comment(linker, "/STACK:1024000000,1024000000") //#pragma GCC optimize (2) //#pragma G++ optimize (2)using namespace std; //const ll mod; const ll MAXN=3e5+10; inl ll read() { re ll x = 0; re int f = 1; char ch = getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch== ‘-‘ ) f = -1; ch = getchar(); } while(ch>=‘0‘&&ch<=‘9‘) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x * f; } inl char readc() { char ch=getchar(); while((‘z‘<ch||ch<‘a‘)&&(‘Z‘<ch||ch<‘A‘)) ch=getchar(); return ch; } inl void write(re ll x){ if(x>=10)write(x/10); putchar(x%10+‘0‘); } inl void writeln(re ll x){ if(x<0) {x=-x;putchar(‘-‘);} write(x); puts(""); } inl ll gcd(re ll x,re ll y){while(y^=x^=y^=x%=y);return x;} inl void FR() { freopen(".in","r",stdin); freopen(".out","w",stdout); } inl void FC() { fclose(stdin); fclose(stdout); } struct Node { ll u,v,w,nxt; }e[20005<<1]; ll cnt,head[60],ssw[60],g[20005],cost[60],times[60]; bool fl[60],in[60],vis[60]; ll ans[20005]; inl void adde(ll u,ll v,ll w) { e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w; e[cnt].nxt=head[u];head[u]=cnt; } ll d[60][105][2005],n,m; void dp(ll x) { if(vis[x]) return ;vis[x]=1; if(!fl[x]) {//基礎裝備 times[x]=min(times[x],m/cost[x]); for(re ll i=times[x];~i;i--) { for(re ll j=i;j<=times[x];j++) { d[x][i][j*cost[x]]=ssw[x]*(j-i); } } return ; } for(re ll h=head[x];h;h=e[h].nxt) { dp(e[h].v);cost[x]+=e[h].w*cost[e[h].v]; times[x]=min(times[x],times[e[h].v]/e[h].w); } times[x]=min(times[x],m/cost[x]); for(re ll i=times[x];~i;i--) { for(re ll j=1;j<=m;j++) g[j]=-inf;g[0]=0; for(re ll h=head[x];h;h=e[h].nxt) { for(re ll k=m;~k;k--) { re ll sst=-inf; for(re ll l=0;l<=k;l++) {sst=max(sst,g[k-l]+d[e[h].v][i*e[h].w][l]);} g[k]=sst;//花k元能到的最高力量 } } for(re ll j=0;j<=i;j++) { for(re ll l=0;l<=m;l++) { d[x][j][l]=max(d[x][j][l],g[l]+ssw[x]*(i-j)); } } } } int main(){ // FR(); n=read(),m=read(); memset(times,inf,sizeof(times)); memset(d,-inf,sizeof(d)); for(re ll i=1;i<=n;i++) { ssw[i]=read(); char sj[3];scanf("%s",sj); if(sj[0]==‘A‘) { fl[i]=1;re ll c=read(); for(re ll j=1;j<=c;j++) { re ll sx=read(),xs=read(); if(!in[sx]) in[sx]=1; adde(i,sx,xs); } } else if(sj[0]==‘B‘) { fl[i]=0;cost[i]=read(); times[i]=read(); } else puts("RE"); } for(re ll i=1;i<=n;i++) { if(!in[i]) {//被坑無數次 dp(i); for(re ll j=m;~j;j--) { for(re ll k=0;k<=j;k++) { ans[j]=max(ans[j],ans[j-k]+d[i][0][k]); } } } } writeln(ans[m]); // FC(); return 0; }
[JSOI2008]魔獸地圖