BZOJ4216: Pig 恶心题+前缀和
BZOJ4177: Mike的农场 最小割+网络流

BZOJ4247: 挂饰 dp

shinbokuow posted @ Sep 02, 2015 10:35:58 PM in BZOJ with tags DP , 1110 阅读

 

题解:

首先注意到假如目前的树上能够插入$n$个节点,那么插入一个能够插入$m$个节点的节点,无论这个节点接在原来的一个位置上,还是这个节点成为新的树的根节点,这棵树都能够插入$n+m-1$个节点。

也就是说,树的形态我们并不需要考虑,只需要考虑这棵树能够插入多少节点。

我们考虑令$f[i][j]$表示前$i$种物品形成的树,树中能够插入$j$个节点的最大价值。

显然利用背包就可以做了。

我加了一点优化:对于$m=0$的节点最后一起贪心的考虑。

虽然复杂度依然是$O(n^2)$,但是我跑得很快目前是rank1。

代码:

 

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;

#define N 2010
int f[2][N];

int a[N],b[N],c[N];

inline void maxi(int&x,int y){
	if(x<y)
		x=y;
}
inline bool cmp(const int&a,const int&b){
	return a>b;
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("tt.in","r",stdin);
#endif
	int n;
	scanf("%d",&n);
	int n1=0,n2=0,i,j,_a,_b;
	for(i=1;i<=n;++i){
		scanf("%d%d",&_a,&_b);
		if(_a==0)
			c[++n2]=_b;
		else{
			a[++n1]=_a;
			b[n1]=_b;
		}
	}
	int now=0,last=1;
	for(i=0;i<=n;++i)
		f[now][i]=-2000000001;
	f[now][1]=0;
	for(i=1;i<=n1;++i){
		swap(now,last);
		for(j=0;j<=n;++j)
			f[now][j]=f[last][j];
		for(j=0;j<=n;++j)
			maxi(f[now][min(n,j+a[i]-1)],f[last][j]+b[i]);
	}
	sort(c+1,c+n2+1,cmp);
	for(i=1;i<=n;++i)
		c[i]=c[i-1]+(c[i]>0?c[i]:0);
	int ans=0;
	for(j=0;j<=n;++j)
		if(f[now][j]!=-2000000001)
				maxi(ans,f[now][j]+c[j]);
	cout<<ans<<endl;
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter