绍兴一中模拟赛10.27——球

本文探讨了一种特殊的背包问题,其中物品的选取受到后续物品移除的限制。通过将物品的重量视为a[i],价值视为b[i],利用动态规划求解最大价值。文章详细解释了如何避免物品间的影响,并提供了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

众所周知AKKing_FB有n(n&lt;=5000)n(n&lt;=5000)n(n<=5000)个球,第i个球有两个属性a[i],b[i]a[i],b[i]a[i],b[i]AKKingFBAKKing_FBAKKingFB想从中取出一些球,使得这些球的b[i]b[i]b[i]之和最大。
但是这题有些奇怪的条件:
1.1.1.AKKingFBAKKing_FBAKKingFB取走第i颗球时,从第iii颗球到i+a[i]−1i+a[i]-1i+a[i]1的球都会被丢掉(需要满足i+a[i]−1&lt;=ni+a[i]-1&lt;=ni+a[i]1<=n)。然后剩余的球会重新并在一起。
2.AKKingFB2. AKKing_FB2.AKKingFB可以主动把当前位于第一位的球放到末尾。之后的球顺次往前。如右边所示 1,2,3,4….n−1,n−−&gt;2,3,4,…n−1,n,11,2,3,4….n-1,n--&gt;2,3,4,…n-1,n,11,2,3,4.n1,n>2,3,4,n1,n,1
AKKingFBAKKing_FBAKKingFB想知道他可以得到的b[i]b[i]b[i]之和的最大值。

Solution

a[i]a[i]a[i]看作重量,b[i]b[i]b[i]看作价值,以nnn为容量做一遍背包即可
很多人会疑惑:取了一个数之后不是会把后面的几个数也丢掉吗?但事实上,可以先把不会影响别的数的数取掉,再取这个数
感性理解就是鸽巢原理
下面理性分析一下:
设选出的位置为pos1...npos_{1...n}pos1...n
如果每个数都会影响别的数,那么
pos2−pos1+1&gt;a1pos_2-pos_1+1&gt;a_1pos2pos1+1>a1
pos3−pos2+1&gt;a2pos_3-pos_2+1&gt;a_2pos3pos2+1>a2

posn−posn−1+1&gt;an−1pos_n-pos_{n-1}+1&gt;a_{n-1}posnposn1+1>an1
pos1−posn+1&gt;anpos_1-pos_n+1&gt;a_npos1posn+1>an
左右两边分别相加,得:Σa&gt;n\Sigma a&gt;nΣa>n
但是因为背包容量为nnn,所以背包计算出的方案不可能有这种情况

Code

#include<bits/stdc++.h>
using namespace std;
const int N=5002;
int n,i,j,f[N],x,y;
inline char gc(){
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(){
	int x=0,fl=1;char ch=gc();
	for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
	for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
	return x*fl;
}
int main(){
	n=rd();
	for (i=1;i<=n;i++){
		x=rd();y=rd();
		for (j=n;j>=x;j--) f[j]=max(f[j],f[j-x]+y);
	}
	printf("%d",f[n]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值