「题解」能量项链

在火星上,能量项链的珠子通过特定规则合并以释放能量。本问题旨在找到最佳合并顺序,使得项链释放的最大能量达到最优。动态规划是解决这个问题的关键,状态转移方程为f[l][r] = max(f[l][k] + f[k + 1][r] + a[l] * a[k + 1] * a[r + 1])。样例输入为4个珠子,最优解的能量为710。

Problem Description

 在Mars星球上,每个Mars人都随身佩带着一串能量项链。在项链上有N颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为m*r*n(Mars单位),新产生的珠子的头标记为m,尾标记为n。


 需要时,Mars人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。


 例如:设N=4,4颗珠子的头标记与尾标记依次为(2,3) (3,5) (5,10) (10,2)。我们用记号⊕表示两颗珠子的聚合操作,(j⊕k)表示第j,k两颗珠子聚合后所释放的能量。则第4、1两颗珠子聚合后释放的能量为:

 (4⊕1)=10*2*3=60。

 这一串项链可以得到最优值的一个聚合顺序所释放的总能量为

 ((4⊕1)⊕2)⊕3)=10*2*3+10*3*5+10*5*10=710。

Input 

 有多组测试数据。


 对于每组测试数据,输入的第一行是一个正整数N(4≤N≤100),表示项链上珠子的个数。第二行是N个用空格隔开的正整数,所有的数均不超过1000。第i个数为第i颗珠子的头标记(1≤i≤N),当i<N时,第i颗珠子的尾标记应该等于第i+1颗珠子的头标记。第N颗珠子的尾标记应该等于第1颗珠子的头标记。


 至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

<think>我们已知用户的问题是关于百度之星2022竞赛题目BD202229项链的解题思路或题解。根据引用[4],题目描述如下:C题:小B想给她的新项链染色。现在有m种颜色,对于第i种颜色,小B有a_i单位的颜料,每单位颜料可以染项链的一个子;同时,小B对于第i种颜色喜爱度为b_i。已知项链有n个子,求染色后每个子的颜色的喜爱度之和的最大值。(每个子只能至多被染一次,不被染色则喜爱度为0)但是,用户提到的题目编号是BD202229,而引用[4]中没有明确编号,但内容相似。因此,我们认定引用[4]即BD202229题目。分析问题:我们有n个子和m种颜色。每种颜色i有两个属性:a_i(可用颜料单位数)和b_i(喜爱度)。每单位颜料可以染一个子,每个子只能染一种颜色或不染色(不染色则喜爱度为0)。我们的目标是最大化所有染色的子的喜爱度之和。策略:由于每个子染上某种颜色的喜爱度只与颜色本身有关,即如果某个子用颜色i染色,则贡献b_i。显然,为了最大化总和,我们希望尽可能用喜爱度高的颜色去染尽可能多的子,但同时受到每种颜色的颜料数量限制。这是一个典型的贪心问题。我们应优先使用喜爱度高的颜色,直到该颜色的颜料用完或者所有子都被染色。具体步骤:1.将颜色按照喜爱度b_i从大到小排序。这样我们可以优先使用喜爱度高的颜色。2.按排序后的顺序遍历颜色,对于当前颜色i,我们最多可以染min(a_i,剩余子数量)个子,然后贡献min(a_i,剩余子数量)*b_i。3.累加贡献,直到所有颜色用完或者所有子都被染色。注意:这里我们不需要考虑子染色的位置,因为题目只要求总和,与子的位置无关。但是,题目中有一个约束:每个子只能至多被染一次。所以实际上,我们不能让同一个子染多种颜色。而上述贪心方法会优先使用高喜爱度的颜色,然后使用低喜爱度的颜色,并不会重复染色,因为每一步都会减少剩余子的数量。因此,算法为:-将m种颜色按b_i降序排序。-初始化剩余子数=n,总得分=0。-对于每个颜色i(按顺序):当前可用染色次数=min(a_i,剩余子数)总得分+=当前可用染色次数*b_i剩余子数-=当前可用染色次数如果剩余子数为0,则退出循环。这样就能得到最大喜爱度总和。例子:假设有3个子(n=3),2种颜色:颜色1:a1=2,b1=5颜色2:a2=2,b2=4排序:先颜色1(b1=5)然后颜色2(b2=4)用颜色1染2个子:得分=2*5=10剩余子数=3-2=1再用颜色2染1个子:得分=1*4=4总得分=14如果先使用颜色2再使用颜色1:颜色2染2个子(得分=2*4=8),剩余1个子用颜色1染(1*5=5),总得分13。所以降序贪心正确。但注意:有可能某种颜色的颜料很多,但是因为我们按b_i排序,所以即使后面有更大量的低喜爱度颜色,也不会影响。因为我们已经优先用掉了高喜爱度的颜色。因此,这个贪心算法是合理的。代码实现(伪代码):1.输入:n,m,数组a(大小为m),数组b(大小为m)2.创建颜色数组,每个元素为(b_i,a_i),然后按照b_i降序排序。3.初始化:total_score=0remain=n4.遍历排序后的颜色数组:foriinrange(m):use=min(remain,a_i)#当前颜色实际能染的子数total_score+=use*b_iremain-=useifremain==0:break5.输出total_score注意边界:如果颜料总和都不足n,那么最终remain>0,但是后面没有颜色了,所以总得分就是能染的子的喜爱度之和。所以,完整代码(例如C++)可以写为:```cpp#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intmain(){intn,m;cin>>n>>m;vector<pair<longlong,longlong>>colors;//存储(b_i,a_i)for(inti=0;i< m;i++){longlonga,b;cin>>a>>b;colors.push_back(make_pair(b,a));}//按b_i从大到小排序sort(colors.begin(),colors.end(),[](constpair<longlong,longlong>&a,constpair<longlong,longlong>&b){returna.first>b.first;});longlongtotal_score=0;longlongremain=n;for(inti=0;i< m;i++){if(remain<=0)break;longlonguse=min(remain,colors[i].second);total_score+=use*colors[i].first;remain-=use;}cout<< total_score<< endl;return0;}```注意:题目中a_i和b_i可能很大,所以用longlong。但是,用户要求的是题解算法分析。我们给出了贪心的证明和代码结构。另外,我们参考了引用[4]的内容,而引用[4]中的题目描述与用户要求的题目一致,因此我们可以确定这就是BD202229项链题解。总结:本题是一个简单贪心,排序后从大到小依次使用颜色即可。</think> ### 百度之星2022题目BD202229“项链题解 #### 问题描述 给定 $n$ 个子和 $m$ 种颜色,每种颜色 $i$ 有: - $a_i$:可用颜料单位数(1单位颜料染1个子) - $b_i$:该颜色的喜爱度 每个子至多染一种颜色(未染色时喜爱度为0),求最大化所有染色子的喜爱度总和[^4]。 --- #### 算法分析 这是一个典型的**贪心问题**,核心思路是:优先使用单位喜爱度高的颜色染色,以实现总喜爱度最大化。具体步骤如下: 1. **输入处理** - $n$:子总数 - $m$:颜色种类数 - $a_i$, $b_i$:每种颜色的颜料量和喜爱度 2. **贪心策略(核心)** 将颜色按单位喜爱度 $b_i$ **降序排序**,依次处理: - 对于当前最高喜爱度 $b_i$,计算实际可用量: $$\text{use} = \min(\text{剩余子数},\ a_i)$$ - 更新总喜爱度: $$\text{total\_score} \leftarrow \text{total\_score} + \text{use} \times b_i$$ - 更新剩余子数: $$\text{remain} \leftarrow \text{remain} - \text{use}$$ - 重复直到无剩余子或无可用颜料 3. **时间复杂度** - 排序 $O(m \log m)$ + 遍历 $O(m)$,整体 $O(m \log m)$ - 满足竞赛效率要求($m \leq 10^5$) --- #### 正确性证明 贪心策略的最优性基于以下性质: 1. **局部最优性**:每次选择当前最高 $b_i$ 的颜色染色,可获得最大边际收益 2. **无后效性**:剩余子染低喜爱度颜色不会影响已染高喜爱度子的决策 3. **全局最优**:若存在更优解,必出现低喜爱度优先使用的情况,但会违反单位喜爱度优势[^4] --- #### 参考代码(C++) ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int n, m; cin >> n >> m; // 存储颜色属性:(b_i, a_i) vector<pair<long long, long long>> colors(m); for (int i = 0; i < m; i++) { cin >> colors[i].second; // a_i cin >> colors[i].first; // b_i } // 按b_i降序排序 sort(colors.rbegin(), colors.rend()); long long total_score = 0; long long remain = n; // 贪心染色 for (auto [b_i, a_i] : colors) { if (remain <= 0) break; long long use = min(remain, a_i); total_score += use * b_i; remain -= use; } cout << total_score << endl; return 0; } ``` --- #### 关键注意事项 1. **数据类型**:$a_i$, $b_i$ 和结果需用 `long long`(值域可达 $10^9$) 2. **边界处理**:颜料总量不足时,`remain > 0` 仍需输出正确结果 3. **输入顺序**:代码中先读 $a_i$ 后读 $b_i$(与题目描述一致)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值