BZOJ 1190 HNOI2007 梦幻岛宝珠 动态规划

题目大意:01背包,其中weight<=2^30,但是每个weight都能写成a*2^b的形式,其中a<=10,b<=30

直接背包肯定TLE+MLE

考虑到每个weight都能写成a*2^b的形式,显然我们要按照b分层来进行背包

令f[i][j]表示有j*2^i+(w&(1<<i)-1)的空间时的最大价值

首先每层内部先做一个01背包

然后层与层之间再转移

从大到小枚举j 转移方程为f[i][j]=max{f[i][j],f[i][j-k]+f[i-1][min(k*2+((w>>i-1)&1),1000)]}

这个是怎么来的呢?我们首先枚举j,然后枚举同一层花销的空间j-k,那么我们在上一层所能选择的就是k*2+((w>>i-1)&1)

很难理解?来举个栗子吧- -

w=(1000100010)2,i=6,j=(111)2,k=1

那么我们将要更新的是(111100010)2,用来更新这个值的是(110000000)2

k=1,代表本层之间差1,上一层之间就差2

((w>>i-1)&1=1,代表上一层还可以选1(第6位上的1)

我们会在下一层选择(1100010)2的空间,而这个值恰好记录在f[5][3]上

还是理解不能的只能多看几遍这段话了= = 这题真他妈理性愉悦

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,w;
long long f[40][1010],ans;
int main()
{
	int i,j,k,x;
	while(cin>>n>>w,n>0)
	{

		memset(f,0,sizeof f);ans=0;

		for(i=1;i<=n;i++)
		{
			int a=0,b=0;
			scanf("%d%d",&a,&x);
			while(~a&1)
				a>>=1,++b;
			for(j=1000;j>=a;j--)
				f[b][j]=max(f[b][j],f[b][j-a]+x);
		}
		for(i=0;i<=30;i++)
			for(j=1;j<=1000;j++)
				f[i][j]=max(f[i][j],f[i][j-1]);
		for(i=1;i<=min(1000,w);i++)
			ans=max(ans,f[0][i]);
		for(i=1;i<=30&&(1<<i)<=w;i++)
			for(j=min(1000,w>>i);~j;j--)
			{
				for(k=0;k<=j;k++)
					f[i][j]=max(f[i][j],f[i][j-k]+f[i-1][min(k+k+((w>>i-1)&1),1000)]);
				ans=max(ans,f[i][j]);
			}
		cout<<ans<<endl;
	}
	return 0;
}
时间: 2024-10-07 23:15:24

BZOJ 1190 HNOI2007 梦幻岛宝珠 动态规划的相关文章

【题解】 bzoj1190: [HNOI2007]梦幻岛宝珠 (动态规划)

bzoj1190,懒得复制,戳我戳我 Solution: 这道题其实是一个背包(分组背包),但是由于数字比较大,就要重新构造dp式子.啃了三天才懂. \(dp[i][j]\)表示背包容积为\(j*2^i\)时的最大价值. 首先,因为每一个物品一定是\(a*2^b\),我们可以按照\(b\)值先按照普通的分组背包去做,处理出每个\(b\)值所对应的\(dp\)值 然后我们就是要把这些\(dp\)值累积起来,选择每组最大显然不合适,因为有可能每个组都剩下空间,剩余空间累加起来的空间还可以放物品,我们

【bzoj1190】[HNOI2007]梦幻岛宝珠 分层背包dp

题目描述 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值.数据范围:N<=100;W<=2^30,并且保证每颗宝石的重量符合a*2^b(a<=10;b<=30) 输入 输入文件中包含多组数据.每组数据的格式如下:第一行是两个正整数n和W,1≤n≤100,1≤W≤2^30,分别表示宝石的数目和最多能带走的宝石重量.接下来的n行,每行有两个正整数weighti和valuei,1≤weighti≤2^30, 0≤

bzoj 4033 树上染色 - 树形动态规划

有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑 色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的 收益.问收益最大值是多少. Input 第一行两个整数N,K. 接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to). 输入保证所有点之间是联通的. N<=2000,0<=K<=N Output 输出一个正整数,表示收益的最大值. Sampl

BZOJ 1189: [HNOI2007]紧急疏散evacuate( BFS + 二分答案 + 匈牙利 )

我们可以BFS出每个出口到每个人的最短距离, 然后二分答案, 假设当前答案为m, 把一个出口拆成m个表示m个时间, 点u到出口v的距离为d, 那么u->v的[d, m]所有点连边, 然后跑匈牙利去check就行了...其实这道题挺好想但是码量还是挺大的.... ----------------------------------------------------------------------------- #include<cstdio> #include<cstring&

bzoj 1188 [HNOI2007]分裂游戏(SG函数,博弈)

1188: [HNOI2007]分裂游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 733  Solved: 451[Submit][Status][Discuss] Description 聪 聪和睿睿最近迷上了一款叫做分裂的游戏. 该游戏的规则试: 共有 n 个瓶子, 标号为 0,1,2.....n-1, 第 i 个瓶子中装有 p[i]颗巧克力豆,两个人轮流取豆子,每一轮每人选择 3 个瓶子.标号为 i,j,k, 并要保证 i < j ,

bzoj 1187: [HNOI2007]神奇游乐园 插头dp

1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 668  Solved: 337[Submit][Status][Discuss] Description 经 历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游 乐场,专为旅途中疲惫的人设计.娱乐场可以看成是一块大小为n×m的区域,且这个n×m的区域被分成n×m个

[BZOJ 1188] [HNOI2007] 分裂游戏 【博弈论|SG函数】

题目链接:BZOJ - 1188 题目分析 我们把每一颗石子看做一个单个的游戏,它的 SG 值取决于它的位置. 对于一颗在 i 位置的石子,根据游戏规则,它的后继状态就是枚举符合条件的 j, k.然后后继状态就是 j 与 k 这两个游戏的和. 游戏的和的 SG 值就是几个单一游戏的 SG 值的异或和. 那么还是根据 SG 函数的定义 , 即 SG(u) = mex(SG(v)) ,预处理求出每个位置的 SG 值.一个位置的 SG 值与它后面的位置有关,是取决于它是倒数第几个位置,那么我们预处理求

bzoj 1419 Red is good - 动态规划 - 概率与期望

Description 桌面上有R张红牌和B张黑牌,随机打乱顺序后放在桌面上,开始一张一张地翻牌,翻到红牌得到1美元,黑牌则付出1美元.可以随时停止翻牌,在最优策略下平均能得到多少钱. Input 一行输入两个数R,B,其值在0到5000之间 Output 在最优策略下平均能得到多少钱. Sample Input 5 1 Sample Output 4.166666 HINT 输出答案时,小数点后第六位后的全部去掉,不要四舍五入. (题目太简洁,不需要大意) 这道题和poj的Collecting

BZOJ 1560 JSOI2009 火星藏宝图 动态规划

题目大意:给定一个m*m的矩阵,上面有n个点,每个点上有一个正的收益,在两个点之间走的代价是距离的平方,求(1,1)到(m,m)的最大收益 直接排序并且DP的方法很容易想到 但是显然O(n^2)过不去 考虑平方的特性 由于A和B都大于等于0时(A+B)^2>=A^2+B^2 因此A->B->C一定比A->C更优 根据这个特性,我们可以将点按照纵坐标为第一键值,横坐标为第二键值排序 对于每一列我们维护一个当前纵坐标最大的点 用这个点更新一定比它下面的点更新更优 因此对于每个点枚举横坐