【ZOJ】3812 We Need Medicine

这道题就题意来说其实就是一道简单的记录路径的0,1背包,告诉你n个物品,每种物品只能取一次,再有q个询问,问你是否能在满足选出物品的w之和为m的情况下,满足t之和为s的情况,若可以则任意输出一种方案。

因此我们可以设计状态,dp[i][j][k]为前i个物品选出部分,当t之和为j时,w之和为k的情况能否满足,若存在方案则为1,不存在则为0。而状态的转移方程也是很简单。

dp[i][j+t[i]][k+w[i]] = dp[i-1][j][k]。但是这样会超时,超时的原因是因为大量进行了重复的动作(即k的枚举)。因此可以用二进制来表示在当前j下可以表示的k的状态,然后通过位运算来快速进行所有k的推导,使得整个维度降低了一维,这样再记录路径就可以做了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int SIZEN = 200505;
const int M = 55;
int w[1005],t[1005];
LL dp[SIZEN];
LL has[1005];
int pre[SIZEN][55];
int ans[1000];
LL lowbit(LL x){
	return x & (-x);
}
void solve(){
	int n,q;
	scanf("%d%d",&n,&q);
	for(int i = 0 ; i < n ; i ++)
		scanf("%d%d",&w[i],&t[i]);
	memset(dp,0,sizeof(dp));
	dp[0] = 1;
	for(int i = 0 ; i < n ; i ++){
		for(int j = SIZEN - 5; j >= t[i] ;j --){
			LL tmp = dp[j];
			dp[j] |= (dp[ j - t[i] ]<<w[i]) & ((1ll<<(M + 1)) - 1);
			for(LL k = tmp ^ dp[j] ; k ; k -= lowbit(k)){
				LL tt = lower_bound(has,has+M,lowbit(k)) - has;
				pre[j][tt] = i;
			}
		}
	}
	int m,s;
	for(int i = 0 ; i < q ; i ++){
		scanf("%d%d",&m,&s);
		if(!(dp[s] & (1ll<<m))) printf("No solution!\n");
		else{
			int cnt = 0;
			while(s){
				int id = pre[s][m];
				ans[cnt++] = id + 1;
				s -= t[id];
				m -= w[id];
			}
			for(int i = 0 ; i < cnt - 1; i++) printf("%d ",ans[i]);
			printf("%d\n",ans[cnt - 1]);
		}
	}
}
int main()
{
	int _;
	scanf("%d",&_);
	for(int i = 0 ; i < M ; i++) has[i] = (1ll<<i);
	while(_--) solve();
}
时间: 2024-10-06 19:12:16

【ZOJ】3812 We Need Medicine的相关文章

【ZOJ】3380 Patchouli&#39;s Spell Cards

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3957 题意:m个位置,每个位置填1~n的数,求至少有L个位置的数一样的概率(1<=n,m,l<=100) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct inum { static const int N=205,

【ZOJ】3785 What day is that day? ——浅谈KMP应用之ACM竞赛中的暴力打表找规律

首先声明一下,这里的规律指的是循环,即找到最小循环周期.这么一说大家心里肯定有数了吧,“不就是next数组性质的应用嘛”. 先来看一道题 ZOJ 3785 What day is that day? Time Limit: 2 Seconds      Memory Limit: 65536 KB It's Saturday today, what day is it after 11 + 22 + 33 + ... + NN days? Input There are multiple tes

【ZOJ】3430 Detect the Virus

动态建树MLE.模仿别人的代码模板各种原因wa后,终于AC. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 7 #define MAXN 515*70 8 #define NXTN 256 9 10 bool visit[515]; 11 char str[3005]; 12 unsigned

【有上下界网络流】【ZOJ】2314 Reactor Cooling

[算法]有上下界网络流-无源汇(循环流) [题解] 无源汇网络流相当于重建图后跑最大流. 循环流要求每个点(或边)的流入量和流出量相等. http://www.cnblogs.com/liu-runda/p/6262832.html http://hzwer.com/3356.html 入度>出度时(in[x]>0)时,需要流出去,所以从源向点引一条边,引诱它流出去. 入度<出度时(in[x]<0)时,需要流进来,所以从点向汇引一条边,引诱它流进来. 为何这样正确?源和汇的作用只是

【ZOJ】【3329】One Person Game

概率DP kuangbin总结题目中的第三道 看来还是没有进入状态啊……都说是DP了……当然是要找[状态之间的转移关系]了…… 本题中dp[i]跟 dp[i-(k1+k2+k3)] 到dp[i-1]都有关系……然后所有的dp[i]都跟dp[0]即ans有关…… 用[系数]进行转移……sigh最近越来越水了 1 //BZOJ 1000 2 #include<cmath> 3 #include<vector> 4 #include<cstdio> 5 #include<

【ZOJ】Nice Patterns Strike Back(矩阵快速乘法)

dp[[i][j] = sum(dp[i - 1][k]) (k -> j) 状态方程,因为N很大而M很小,所以第一时间可以想到矩阵优化 可能之前没做过类似的题被卡的很厉害. 另外用C++写大数真心麻烦.. #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 45; const int maxd = 30005; char n[ma

【ZOJ】3329 One Person Game

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3754 题意:有三个色子,分别有k1.k2.k3个面,权值分别是1-k1, 1~k2, 1~k3,等概率朝上.如果朝上的面分别为a.b.c,则分数置0,否则累加权值和.当权值和>n时则结束,求期望次数.T组数据.(T<=300; 1<k1,k2,k3<=6) #include <cstdio> #include <cstring> usin

【ZOJ】3640 Help Me Escape

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4808 题意:一个吸血鬼初始攻击力为f.n条路,他每次等概率选择一条路.如果攻击力大于这条路的c[i],则花费t[i]天逃出($t[i]=\frac{1+\sqrt{5}}{2} \times c[i]^2$),否则花费1天的时间继续选择路.问逃出去的期望天数(1<=c[i], f<=10000) #include <cstdio> #include <cm

【ZOJ】1015 Fishing Net

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1015 题意:给出一个n个点的无向图,询问是否为弦图,弦图定义为对于图中任意长度>3的环一定存在环上不相邻的点有边相连(n<=1000) #include <bits/stdc++.h> using namespace std; const int N=1005; int n, m, ihead[N], cnt, tag[N], pos[N]; bool vi