首页 > 其他分享 >luogu2647题解

luogu2647题解

时间:2024-02-05 19:55:05浏览次数:30  
标签:ch luogu2647 int 题解 read MAXN 物品 dp

首先这道题没有规定选几个。
一开始我以为是全选,然后想了个贪心才发现看错了。
那我们先来假设选 \(m\) 个。

这个题的每个物品都会影响后面物品的收益,不好看。

由于每个物品 \(i\) 对后选的其他物品减少的收益都是 \(R_i\),因此我们在保证总价值不变的情况下转化一下,把该物品的价值改为本身的收益和减少后面物品的收益的差。

设物品 \(i\) 是第 \(t_i\) 次被选到,则该物品的价值为 \(W_i-(m-t_i)R_i\)​。

好像还不是很好看,因为我们不知道这个 \(m\)​ 应该多大。

有的时候要用逆向思维思考,所以我们不妨反过来想。
我们可以先考虑最后一个,再考虑倒数第二个,然后向前推进,这样我们重新设一下 \(t_i\) 为我们倒着考虑的顺序,那么该物品的价值为 \(W_i-t_iR_i\)。

这样就非常的清爽,因为我们不需要考虑 \(m\),可以直接从 \(1\) 个数推到 \(n\)​ 个数的情况。

每个数只能选一次,然后求选 \(m\) 数的最优值,价值不一不好贪心,由此可以想到 01 背包。

但是直接跑 01 背包还是错的。附一份全 WA 代码。

constexpr int MAXN=3e3+10;
int n,dp[MAXN];
struct item{
	int w,r;
}t[MAXN];
int main(){
    n=read<int>();
    for(int i=1;i<=n;++i){
        t[i].w=read<int>();t[i].r=read<int>();
    }
    for(int i=1;i<=n;++i){
        for(int j=i;j>=1;--j){
            dp[j]=max(dp[j],dp[j-1]+t[i].w-(j-1)*t[i].r);
        }
    }
    int ans=0;
    for(int i=1;i<=n;++i)ans=max(ans,dp[i]);
    printf("%d\n",ans);
    return 0;
}

这样的 01 背包并不能覆盖到所有情况,至少是可能为最优解的情况。
很容易发现其中的 \(dp_n\) 只有从 \(1\) 选到 \(n\) 的情况。
然而跑 \(n\) 遍这个过程不仅会超时,而且会把这个问题写成一个完全背包。

好像没什么思路,我们再来研究题目的性质。

容易发现,在选择的物品固定的情况下,该选择的方案的好坏只与选择顺序和他们对其他物品影响的 \(R_i\) 有关,我们在贪心思想的基础上可以先选 \(R_i\) 小的物品 \(i\)。

在选择的物品固定的情况下,我们会得到一种选择的顺序,会排除掉一些不优的情况。
我们通过比较 \(R_i\) 对物品进行排序,得到了物品选择的顺序,在这个基础上跑 01 背包解决选哪些数的问题,即可得到最优解。
一个细节就是由于我们是倒着考虑的,所以应该把 \(R_i\) 大的物品放在前面。

代码如下。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
constexpr int MAXN=3e3+10;
int n,dp[MAXN];
struct item{
	int w,r;
}t[MAXN];
template<typename T>
T read(){
	T f=1,x=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
	return f*x;
}
namespace sol{
	bool cmp(item x,item y){
		return x.r>y.r;
	}
	void solve(){
		n=read<int>();
		for(int i=1;i<=n;++i){
			t[i].w=read<int>();t[i].r=read<int>();
		}
		sort(t+1,t+n+1,cmp); 
		for(int i=1;i<=n;++i){
			for(int j=i;j>=1;--j){
				dp[j]=max(dp[j],dp[j-1]+t[i].w-(j-1)*t[i].r);
			}
		}
		int ans=0;
		for(int i=1;i<=n;++i)ans=max(ans,dp[i]);
		printf("%d\n",ans);
	}
}
int main(){
	sol::solve();
	return 0;
}

标签:ch,luogu2647,int,题解,read,MAXN,物品,dp
From: https://www.cnblogs.com/LiJoQiao/p/18008725

相关文章

  • P10125 「Daily OI Round 3」Simple 题解
    题目传送门简单模拟,主要考察字符串。首先输入一个char类型的数组,然后直接遍历每一位是否为Acoipp或Svpoll即可。//Simple//codeby:cq_irritater//time:2024/02/04#include<bits/stdc++.h>usingnamespacestd;chara[10];intmain(){//freopen("c......
  • 中文数字的应用及其问题解决之道
    中文数字,也称汉字数字,是中文语言中表示数字的一种方式。它们不仅有着悠久的历史和文化背景,还在日常生活中发挥着重要的作用。本文将探讨中文数字的应用领域,并介绍它们如何解决实际问题。中文数字-阿拉伯数字转换|一个覆盖广泛主题工具的高效在线平台(amd794.com)https:/......
  • P2367 语文成绩 题解
    语文成绩题目背景语文考试结束了,成绩还是一如既往地有问题。题目描述语文老师总是写错成绩,所以当她修改成绩的时候,总是累得不行。她总是要一遍遍地给某些同学增加分数,又要注意最低分是多少。你能帮帮她吗?输入格式第一行有两个整数\(n\),\(p\),代表学生数与增加分数的次数。......
  • 题解 ARC171D【Rolling Hash】
    来补题了。昨天赛时想法是对的,代码写错了,没调过太可惜了。显然\(P>n\)时必定有解。设前缀\([1,i]\)的哈希值为\(s_i\),显然\([l,r]\)的哈希值不为\(0\)的充要条件是\(s_{l-1}\nes_r\)。建立一个点的编号为\(0\simn\)的图,对于每个输入的区间\([l,r]\),连接一条边......
  • 【洛谷 P2437】蜜蜂路线 题解(递归+记忆化搜索+高精度)
    蜜蜂路线题目描述一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你:蜜蜂从蜂房开始爬到蜂房,,有多少种爬行路线?(备注:题面有误,右上角应为)输入格式输入的值输出格式爬行有多少种路线样例#1样例输入#1114样例输出#1377提示对于100%的......
  • 题解 ARC171C【Swap on Tree】
    每棵子树内只可能有至多一个外来的数,且外来的数是多少并不影响方案数,因此考虑设\(f_{u,i,0/1}\)表示考虑以\(u\)为根的子树,与\(u\)相连的所有边中断了\(i\)条,且\(u\)与其父亲之间的边有没有断的方案数。设\(g_{u,c}=\sumf_{u,i,c}\)。每个节点的初始状态是\(f_{u,0,......
  • 题解 ARC171B【Chmax】
    考察题面中的操作究竟做了什么,不难发现其实是将所有满足\(P_i>i\)的\(i\toP_i\)连边,得到若干条链,然后\(B_i\)即为\(i\)所在链的最后一个节点。显然,存在\(A_i<i\)时无解,存在\(A_i\nei\)但\(A_j=i\)时也无解。否则,每个\(A_i\nei\)的位置填的数都唯一确定......
  • [ABC238F] Two Exams 题解
    题目链接题意有\(N\)个人,有两个\(1\simN\)排列\(P,Q\),在其中选择\(K\)个数,要满足:如果\(P_x<P_y\)且\(Q_x<Q_y\)则不能选了\(y\)而不选\(x\)。思路首先按照\(P\)从小到大排序,这样的话只用考虑\(Q\)。设\(f_{i,j,k}\)表示从前\(i\)个数中选\(j\)个,其中......
  • 【题解】U405180 计算平方和
    \(\mathbf{Part\0}\)目录\(/\\mathbf{Contents}\)\(\mathbf{Part\1}\)题目大意\(/\\mathbf{Item\content}\)\(\mathbf{Part\2}\)题解\(/\\mathbf{Solution}\)\(\mathbf{Part\2.1}\text{C}\)++神奇整数类型之\(\text{__int128}/......
  • [ARC162D] Smallest Vertices 题解
    题目链接点击打开链接题目解法这种树的形态计数题首先可以想到\(prufer\)序列计数,如果没有任何限制,那么方案数为\(\prod\frac{(n-2)!}{deg_i}\),其中\(deg_1=d_1-1,deg_i=d_i(2\lei\len)\)对于每个点分开求贡献考虑这个式子只和点的个数和子树内的\(\sumdeg\)有关......