P2392 kkksc03考前临时抱佛脚
题目背景
kkksc03 的大学生活非常的颓废,平时根本不学习。但是,临近期末考试,他必须要开始抱佛脚,以求不挂科。
题目描述
这次期末考试,kkksc03 需要考 4 科。因此要开始刷习题集,每科都有一个习题集,分别有 s1,s2,s3,s4 道题目,完成每道题目需要一些时间,可能不等(A1,A2,...,As1,B1,B2,...,Bs2,C1,C2,...,Cs3,D1,D2,...,Ds4)。
kkksc03 有一个能力,他的左右两个大脑可以同时计算 2 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。
由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。
输入格式
本题包含 5 行数据:第 1 行,为四个正整数 s1,s2,s3,s4。
第 2 行,为 A1,A2,...,As1 共 s1 个数,表示第一科习题集每道题目所消耗的时间。
第 3 行,为 B1,B2,...,Bs2 共 s2 个数。
第 4 行,为 C1,C2,...,Cs3 共 s3 个数。
第 5 行,为 D1,D2,...,Ds4 共 s4 个数,意思均同上。
输出格式
输出一行,为复习完毕最短时间。
输入输出样例
输入 #1
1 2 1 3
5
4 3
6
2 4 3
输出 #1
20
说明/提示
1≤s1,s2,s3,s4≤20。
1≤A1,A2,...,As1,B1,B2,...,Bs2,C1,C2,...,Cs3,D1,D2,...,Ds4≤60。
解法
这里我们可以把四个科目的总时间分别求出来,然后再用累加器加起来就可以了,这里就是一个01背包的题目,这里的内循环应该从sum/2到v[i],因为复习的最短时间就是sum/2
题解
for(int k=1;k<=4;k++)
{
int sum=0;
for(int j=1;j<=s[k];j++)
{
cin>>a[j];
sum+=a[j];
}
memset(dp,0,sizeof dp);
for(int i=1;i<=s[k];i++)
for(int j=sum/2;j>=a[i];j--)
dp[j]=max(dp[j],a[i]+dp[j-a[i]]);
res+=sum-dp[sum/2];
}
P1466 [USACO2.2] 集合 Subset Sums
题目描述
对于从 1∼n 的连续整数集合,能划分成两个子集合,且保证每个集合的数字和是相等的。举个例子,如果 n=3,对于 {1,2,3} 能划分成两个子集合,每个子集合的所有数字和是相等的:
{3} 和 {1,2} 是唯一一种分法(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数)
如果 n=7,有四种方法能划分集合 {1,2,3,4,5,6,7},每一种分法的子集合各数字和是相等的:
{1,6,7} 和 {2,3,4,5}
{2,5,7} 和 {1,3,4,6}
{3,4,7} 和 {1,2,5,6}
{1,2,4,7} 和 {3,5,6}
给出 n,你的程序应该输出划分方案总数。
输入格式
输入文件只有一行,且只有一个整数 n
输出格式
输出划分方案总数。
输入输出样例
输入 #1
7
输出 #1
4
说明/提示
【数据范围】
对于 100% 的数据,1≤n≤39。
翻译来自NOCOW
USACO 2.2
解法
最暴力的方法肯定是搜索,但是动态规划也可以做,推导出的状态转移方程:dp[j]=dp[j]+dp[i],那么就可以做了
题解
sum=(n+1)*n/2;
if(sum%2!=0) {cout<<"0";return 0;}
sum/=2;
dp[0]=1;
for(int i=1;i<=n;i++)
for(int j=sum;j>=i;j--)
dp[j]+=dp[j-i];
注意这里要输出dp[sum]/2
错误
没开long long
P2370 yyy2015c01 的 U 盘
题目背景
在 2020 年的某一天,我们的 yyy2015c01 买了个高端 U 盘。
题目描述
你找 yyy2015c01 借到了这个高端的 U 盘,拷贝一些重要资料,但是你发现这个 U 盘有一些问题:
- 这个 U 盘的传输接口很小,只能传输大小不超过 L 的文件。
- 这个 U 盘容量很小,一共只能装不超过 S 的文件。
但是你要备份的资料却有很多,你只能备份其中的一部分。
为了选择要备份哪些文件,你给所有文件设置了一个价值 Vi,你希望备份的文件总价值不小于 p。
但是很快你发现这是不可能的,因为 yyy2015c01 的传输接口太小了,你只有花钱买一个更大的接口(更大的接口意味着可以传输更大的文件,但是购买它会花费更多的钱)。
注意:你的文件不能被分割(你只能把一个文件整个的传输进去,并储存在U盘中),
你放在 U 盘中文件的总大小不能超过 U 盘容量。
现在问题来了:你想知道,在满足 U 盘中文件价值之和不小于 p 时,最小需要多大的接口。
输入格式
第 1 行,三个正整数 n,p,S 分别表示文件总数,希望最小价值 p ,U 盘大小。
接下来 n 行,每行两个正整数 Wi,Vi,表示第 i 个文件的大小和价值。
输出格式
输出一个正整数表示最小需要的接口大小。
如果无解输出 No Solution!
。
输入输出样例
输入 #1
3 3 5
2 2
1 2
3 2
输出 #1
2
输入 #2
2 3 500
1 2
500 1
输出 #2
500
输入 #3
3 3 2
2 2
1 2
3 2
输出 #3
No Solution!
输入 #4
4 5 6
5 1
5 2
5 3
1 1
输出 #4
No Solution!
说明/提示
1≤n,Wi,S≤10的3次方,1≤Vi≤10是6次方,1≤p≤10的9次方。
数据较小,请勿乱搞。
样例解释 1:买一个大小为 2 接口,把物品 1 、2 放进U盘。
样例解释 2:买一个大小为 500 的接口。
样例解释 3:本来可以买大小为 2 的接口,可是 U 盘容量放不下足够的文件。
如果数据出现疏漏,请联系出题人 a710128
向本题主人公 yyy2015c01 同学致敬!
解法
这里因为要放的价值不小于p,那么我们就要排序,所以我们要用结构体把w和v存起来,然后排序,就可以做这道题了
题解
struct node
{
int w,v;
}p[1005];
bool cmp(node x,node y)
{
return x.w<y.w;
}
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;i++)
for(int j=s;j>=p[i].w;j--)
{
dp[j]=max(dp[j],dp[j-p[i].w]+p[i].v);
if(dp[j]>=P)
{
cout<<p[i].w;
return 0;
}
}
错误
状态转移方程的dp[j]写成dp[j-1]
P1507 NASA的食物计划
题目背景
NASA(美国航空航天局)因为航天飞机的隔热瓦等其他安全技术问题一直大伤脑筋,因此在各方压力下终止了航天飞机的历史,但是此类事情会不会在以后发生,谁也无法保证。所以,在遇到这类航天问题时,也许只能让航天员出仓维修。但是过多的维修会消耗航天员大量的能量,因此 NASA 便想设计一种食品方案,使体积和承重有限的条件下多装载一些高卡路里的食物。
题目描述
航天飞机的体积有限,当然如果载过重的物品,燃料会浪费很多钱,每件食品都有各自的体积、质量以及所含卡路里。在告诉你体积和质量的最大值的情况下,请输出能达到的食品方案所含卡路里的最大值,当然每个食品只能使用一次。
输入格式
第一行 2 个整数,分别代表体积最大值 h 和质量最大值 t。
第二行 1 个整数代表食品总数 n。
接下来 n 行每行 3 个数 体积 hi,质量 ti,所含卡路里 ki。
输出格式
一个数,表示所能达到的最大卡路里(int
范围内)
输入输出样例
输入 #1
320 350
4
160 40 120
80 110 240
220 70 310
40 400 220
输出 #1
550
说明/提示
对于 100% 的数据,h,t,hi,ti≤400,n≤50,ki≤500。
解法
这里因为有两种w,所以我们要定义一个三维dp,当然我们可以用二维优化,其他没有什么区别
题解
for(int i=1;i<=n;i++)
for(int j=h;j>=w1[i];j--)
for(int k=t;k>=w2[i];k--)
dp[j][k]=max(dp[j][k],dp[j-w1[i]][k-w2[i]]+v[i]);
P1855 榨取kkksc03
题目描述
洛谷 2 的团队功能是其他任何 OJ 和工具难以达到的。借助洛谷强大的服务器资源,任何学校都可以在洛谷上零成本的搭建 OJ 并高效率的完成训练计划。
为什么说是搭建 OJ 呢?为什么高效呢?

因为,你可以上传私有题目,团队外别人是无法看到的。我们还能帮你们评测!
你可以创建作业,给组员布置任务,查看组员的完成情况,还可以点评任意一份代码!
你可以创建比赛!既可以是 OI 赛制还可以是 ICPC 赛制!既可以是团队内部的私有比赛,也可以公开赛,甚至可以指定谁可以参加比赛。这样,搞"x 校联赛"最合适不过了。洛谷凭借这个功能,希望能够提供公开及私有比赛的另外一个平台。

值得说明的是,本次比赛就是采用团队私有题目+邀请比赛的机制。
洛谷的运营组决定,如果一名 OIer 向他的教练推荐洛谷,并能够成功的使用(成功使用的定义是:该团队有 20 个或以上的成员,上传 10 道以上的私有题目,布置过一次作业并成功举办过一次公开比赛),那么他可以浪费掉 kkksc03 的一些时间的同时消耗掉 kkksc03 的一些金钱以满足自己的一个愿望。
kkksc03 的时间和金钱是有限的,所以他很难满足所有同学的愿望。所以他想知道在自己的能力范围内,最多可以完成多少同学的愿望?
输入格式
第一行三个整数 n,M,T,表示一共有 n(1≤n≤100)个愿望, kkksc03 的手上还剩 M(0≤M≤200)元,他的暑假有 T(0≤T≤200)分钟时间。
第 2~n+1 行 mi , ti 表示第 i 个愿望所需要的金钱和时间。
输出格式
一行,一个数,表示 kkksc03 最多可以实现愿望的个数。
输入输出样例
输入 #1
6 10 10
1 1
2 3
3 2
2 5
5 2
4 3
输出 #1
4
解法
kkksc03疯了吗...
这里我们跟上一道题差不多,因为输入的两个输都是w,所以我们将v的每一个数设置成1,其他和上道题差不多
题解
for(int i=1;i<=n;i++)
{
cin>>w1[i]>>w2[i];
v[i]=1;
}
for(int i=1;i<=n;i++)
for(int j=h;j>=w1[i];j--)
for(int k=t;k>=w2[i];k--)
dp[j][k]=max(dp[j][k],dp[j-w1[i]][k-w2[i]]+v[i]);
P1509 找啊找啊找GF
题目背景
"找啊找啊找 GF,找到一个好 GF,吃顿饭啊拉拉手,你是我的好 GF。再见。"
"诶,别再见啊..."
七夕... 七夕... 七夕这个日子,对于 sqybi 这种单身的菜鸟来说是多么的痛苦... 虽然他听着这首叫做"找啊找啊找 GF"的歌,他还是很痛苦。为了避免这种痛苦,sqybi 决定要给自己找点事情干。他去找到了七夕模拟赛的负责人 zmc MM,让她给自己一个出题的任务。经过几天的死缠烂打,zmc MM 终于同意了。
但是,拿到这个任务的 sqybi 发现,原来出题比单身更让人感到无聊 -_- ... 所以,他决定了,要在出题的同时去办另一件能够使自己不无聊的事情------给自己找 GF。
题目描述
sqybi 现在看中了 n 个 MM,我们不妨把她们编号 1 到 n。请 MM 吃饭是要花钱的,我们假设请 i 号 MM 吃饭要花 rmb[i] 块大洋。而希望骗 MM 当自己 GF 是要费人品的,我们假设请第 i 号 MM 吃饭试图让她当自己 GF 的行为(不妨称作泡该 MM)要耗费 rp[i] 的人品。而对于每一个 MM 来说,sqybi 都有一个对应的搞定她的时间,对于第 i 个 MM 来说叫做 time[i]。sqybi 保证自己有足够的魅力用 time[i] 的时间搞定第 i 个 MM ^_^。
sqybi 希望搞到尽量多的 MM 当自己的 GF,这点是毋庸置疑的。但他不希望为此花费太多的时间(毕竟七夕赛的题目还没出),所以他希望在保证搞到 MM 数量最多的情况下花费的总时间最少。
sqybi 现在有 m 块大洋,他也通过一段时间的努力攒到了 r 的人品(这次为模拟赛出题也攒 rp 哦~~)。他凭借这些大洋和人品可以泡到一些 MM。他想知道,自己泡到最多的 MM 花费的最少时间是多少。
注意 sqybi 在一个时刻只能去泡一个 MM ------如果同时泡两个或以上的 MM 的话,她们会打起来的...
输入格式
输入的第一行是 n,表示 sqybi 看中的 MM 数量。
接下来有 n 行,依次表示编号为 1,2,3,...,n 的一个 MM 的信息。每行表示一个 MM 的信息,有三个整数:rmb,rp 和 time。
最后一行有两个整数,分别为 m 和 r。
输出格式
你只需要输出一行,其中有一个整数,表示 sqybi 在保证 MM 数量的情况下花费的最少总时间是多少。
输入输出样例
输入 #1
4
1 2 5
2 1 6
2 2 2
2 2 3
5 5
输出 #1
13
说明/提示
sqybi 说:如果题目里说的都是真的就好了...
sqybi 还说,如果他没有能力泡到任何一个 MM,那么他就不消耗时间了(也就是消耗的时间为 0),他要用这些时间出七夕比赛的题来攒 rp...
【数据规模】
对于 20% 的数据,1≤n≤10;
对于 100% 的数据,1≤rmb≤100,1≤rp≤100,1≤time≤1000。
对于 100% 的数据,1≤m,r,n≤100。
解法
因为这里我们有两个w,所以我们这里要定义两个dp来做
题解
for(int i=1;i<=n;i++)
for(int j=m;j>=w1[i];j--)
for(int k=r;k>=w2[i];k--)
{
if(dp[j][k]<dp[j-w1[i]][k-w2[i]]+1)
{
dp[j][k]=dp[j-w1[i]][k-w2[i]]+1;
f[j][k]=f[j-w1[i]][k-w2[i]]+v[i];
}
else if(dp[j][k]==dp[j-w1[i]][k-w2[i]]+1&&f[j][k]>f[j-w1[i]][k-w2[i]]+v[i]) f[j][k]=f[j-w1[i]][k-w2[i]]+v[i];
}
好长的代码...
注意最后输出的是f数组的内容
P1616 疯狂的采药
题目背景
此题为纪念 LiYuxiang 而生。
题目描述
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:"孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。"
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
-
每种草药可以无限制地疯狂采摘。
-
药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
输入格式
输入第一行有两个整数,分别代表总共能够用来采药的时间 t 和代表山洞里的草药的数目 m。
第 2 到第 (m+1) 行,每行两个整数,第 (i+1) 行的整数 ai,bi 分别表示采摘第 i 种草药的时间和该草药的价值。
输出格式
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
输入输出样例
输入 #1
70 3
71 100
69 1
1 2
输出 #1
140
说明/提示
数据规模与约定
- 对于 30% 的数据,保证 m≤103 。
- 对于 100% 的数据,保证 1≤m≤10的4次方,1≤t≤10的7次方,且 1≤m×t≤10的7次方,1≤ai,bi≤10的4次方。
解法
完全背包,只需要改一下内层循环的范围就可以了
题解
for(int i=1;i<=n;i++)
for(int j=w[i];j<=t;j++)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
错误
数组范围开小了
P1679 神奇的四次方数
题目背景
在你的帮助下,v 神终于帮同学找到了最合适的大学,接下来就要通知同学了。在班级里负责联络网的是 dm 同学,于是 v 神便找到了 dm 同学,可 dm 同学正在忙于研究一道有趣的数学题,为了请 dm 出山,v 神只好请你帮忙解决这道题了。
题目描述
将一个整数 m 分解为 n 个四次方数的和的形式,要求 n 最小。例如,当 m=706 时,因为 706=5的4次方+3的4次方,所以有 n=2。可以证明此时 n 最小。
输入格式
一行,一个整数 m。
输出格式
一行,一个整数 n。
输入输出样例
输入 #1
706
输出 #1
2
说明/提示
数据范围及约定
- 对于 30% 的数据,m≤5000;
- 对于 100% 的数据,m≤100,000。
解法
将w[i]设置成i的4次方,v[i]置成1就可以做了,因为这里我们这个数的最大范围就是四次方根m,所以可以这么做
题解
for(int i=1;i<=sqrt(sqrt(m));i++)
w[i]=i*i*i*i;
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(int i=1;i<=sqrt(sqrt(m));i++)
for(int j=w[i];j<=m;j++)
dp[j]=min(dp[j],dp[j-w[i]]+1);
错误
因为dp要求最小值,所以我们要把数组设为极大值
P2918 [USACO08NOV] Buying Hay S
题目描述
Farmer John is running out of supplies and needs to purchase H (1 <= H <= 50,000) pounds of hay for his cows.
He knows N (1 <= N <= 100) hay suppliers conveniently numbered 1..N. Supplier i sells packages that contain P_i (1 <= P_i <= 5,000) pounds of hay at a cost of C_i (1 <= C_i <= 5,000) dollars. Each supplier has an unlimited number of packages available, and the packages must be bought whole.
Help FJ by finding the minimum cost necessary to purchase at least H pounds of hay.
约翰的干草库存已经告罄,他打算为奶牛们采购 H(1≤H≤50000) 磅干草。
他知道 N(1≤N≤100) 个干草公司,现在用 1 到 N 给它们编号。第 i 公司卖的干草包重量为 Pi(1≤Pi≤5,000) 磅,需要的开销为 Ci(1≤Ci≤5,000) 美元。每个干草公司的货源都十分充足, 可以卖出无限多的干草包。
帮助约翰找到最小的开销来满足需要,即采购到至少 H 磅干草。
输入格式
* Line 1: Two space-separated integers: N and H
* Lines 2..N+1: Line i+1 contains two space-separated integers: P_i and C_i
输出格式
* Line 1: A single integer representing the minimum cost FJ needs to pay to obtain at least H pounds of hay.
输入输出样例
输入 #1
2 15
3 2
5 3
输出 #1
9
说明/提示
FJ can buy three packages from the second supplier for a total cost of 9.
解法
这里还是完全背包,不过要输出最小的开销,所以我们应该输出j,其他没有什么问题
题解
for(int i=1;i<=n;i++)
for(int j=w[i];j<=5e5;j++)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
int j=5e5;
while(dp[j--]>=h);
cout<<j+2;
错误
j应该最大取到5e5
P5662 [CSP-J2019] 纪念品
题目描述
小伟突然获得一种超能力,他知道未来 T 天 N 种纪念品每天的价格。某个纪念品的价格是指购买一个该纪念品所需的金币数量,以及卖出一个该纪念品换回的金币数量。
每天,小伟可以进行以下两种交易无限次:
- 任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品;
- 卖出持有的任意一个纪念品,以当日价格换回金币。
每天卖出纪念品换回的金币可以立即 用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。
T 天之后,小伟的超能力消失。因此他一定会在第 T 天卖出所有纪念品换回金币。
小伟现在有 M 枚金币,他想要在超能力消失后拥有尽可能多的金币。
输入格式
第一行包含三个正整数 T,N,M,相邻两数之间以一个空格分开,分别代表未来天数 T,纪念品数量 N,小伟现在拥有的金币数量 M。
接下来 T 行,每行包含 N 个正整数,相邻两数之间以一个空格分隔。第 i 行的 N 个正整数分别为 Pi,1,Pi,2,...,Pi,N,其中 Pi,j 表示第 i 天第 j 种纪念品的价格。
输出格式
输出仅一行,包含一个正整数,表示小伟在超能力消失后最多能拥有的金币数量。
输入输出样例
输入 #1
6 1 100
50
20
25
20
25
50
输出 #1
305
输入 #2
3 3 100
10 20 15
15 17 13
15 25 16
输出 #2
217
说明/提示
样例 1 说明
最佳策略是:
第二天花光所有 100 枚金币买入 5 个纪念品 1;
第三天卖出 5 个纪念品 1,获得金币 125 枚;
第四天买入 6 个纪念品 1,剩余 5 枚金币;
第六天必须卖出所有纪念品换回 300 枚金币,第四天剩余 5 枚金币,共 305 枚金币。
超能力消失后,小伟最多拥有 305 枚金币。
样例 2 说明
最佳策略是:
第一天花光所有金币买入 10 个纪念品 1;
第二天卖出全部纪念品 1 得到 150 枚金币并买入 8 个纪念品 2 和 1 个纪念品 3,剩余 1 枚金币;
第三天必须卖出所有纪念品换回 216 枚金币,第二天剩余 1 枚金币,共 217 枚金币。
超能力消失后,小伟最多拥有 217 枚金币。
数据规模与约定
对于 10% 的数据,T=1。
对于 30% 的数据,T≤4,N≤4,M≤100,所有价格 10≤Pi,j≤100。
另有 15% 的数据,T≤100,N=1。
另有 15% 的数据,T=2,N≤100。
对于 100% 的数据,T≤100,N≤100,M≤10的3次方,所有价格 1≤Pi,j≤10的4次方,数据保证任意时刻,小伟手上的金币数不可能超过 10的4次方。
解法
直接不管亏还是赚都去试试,反正dp会帮我们找到答案
题解
for(int k=1;k<t;k++)
{
for(int i=1;i<=n;i++)
{
w[i]=p[k][i];
v[i]=p[k+1][i]-p[k][i];
}
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++)
for(int j=w[i];j<=m;j++)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
m+=dp[m];
}