CF2124B Minimise Sum 题解

题目传送门

题意:

有一个序列,长度为 n n n,需要在至多一次(可以不操作)操作后求出前缀最小值的最小和。

操作:

选择两个数 i , j ( i < j ) i,j(i<j) i,j(i<j),让 a i a_{i} ai 变为 a i + a j a_{i}+a_{j} ai+aj,让 a j a_{j} aj 变为 0 0 0

样例解释:

第一个测试用例:

不操作,答案是 $\min(1) + \min(1,2) = 1 + 1 =2 $。

第二个测试用例:

操作时 i = 2 , j = 3 i = 2,j = 3 i=2,j=3,即将序列变为 1 , 5 , 0 1,5,0 1,5,0,答案是 min ⁡ ( 1 ) + min ⁡ ( 1 , 5 ) + min ⁡ ( 1 , 5 , 0 ) = 1 + 1 + 0 = 2 \min(1)+\min(1,5)+\min(1,5,0) = 1 + 1 + 0 = 2 min(1)+min(1,5)+min(1,5,0)=1+1+0=2

第三个测试用例:

不操作,答案是 min ⁡ ( 3 ) + min ⁡ ( 3 , 0 ) + min ⁡ ( 3 , 0 , 2 ) + min ⁡ ( 3 , 0 , 2 , 3 ) = 3 + 0 + 0 + 0 = 3 \min(3) + \min(3,0) + \min(3,0,2) + \min(3,0,2,3) = 3 + 0 + 0 + 0 = 3 min(3)+min(3,0)+min(3,0,2)+min(3,0,2,3)=3+0+0+0=3

思路

考虑到答案求最小值,只要前面有一个序列元素值为 0 0 0,则后续求最小值也为 0 0 0

所以我们考虑序列 0 0 0 所在的位置。

  • 在第一个位置,不操作,简单推导能够发现,答案为 0 0 0

  • 在第二个位置,考虑进行操作: i = 1 , j = 2 i=1,j=2 i=1,j=2,也就是说答案为 a 1 + a 2 a_{1} + a_{2} a1+a2。因为进行操作后,序列第一个元素为原序列前两个数的和,而序列第二个元素变为了 0 0 0,后续求最小值就是 0 0 0

  • 在第三个位置,考虑进行操作: i = 2 , j = 3 i=2,j=3 i=2,j=3 a 1 a_{1} a1 不变, a 2 a_{2} a2 变为 a 2 + a 3 a_{2} + a_{3} a2+a3 a 3 a_{3} a3 变为 0 0 0,答案为 a 1 + min ⁡ ( a 1 , a 2 + a 3 ) a_{1} + \min(a_{1},a_{2}+a_{3}) a1+min(a1,a2+a3)

  • 在后续位置,答案均不是最优解,可以举例子证明。

  • 不操作,直接计算。

代码:

#include<bits/stdc++.h>
using namespace std;
#define fo(i,begin,end) for(int i=begin;i<=end;++i)
#define of(i,begin,end) for(int i=begin;i>=end;--i)
#define fos(i,begin,end,ADD) for(int i=min(begin,end);i<=max(begin,end);i+=ADD)
#define ofs(i,begin,end,ADD) for(int i=max(begin,end);i>=min(begin,end);i-=ADD)
#define debug(val) cout<<#val<<':'<<(val)<<'\n'
#define debug_1(name,i,x) cout<<#name<<"["<<i<<"]:"<<x<<'\n';
#define debug_2(name,i,j,x) cout<<#name<<"["<<i<<"]["<<j<<"]:"<<x<<"\n";
#define ll long long
#define ull unsigned long long

int main() {
	int t;
	cin>>t;
	while(t--) {
		int n;
		cin>>n;
		int a[n+1];
		int sum=INT_MAX;
		int ans1,ans2,ans3;
		fo(i,1,n){
			cin>>a[i];
			sum=min(sum,a[i]);
			ans1+=sum;
		}
		ans2=a[1]+a[2];
		ans3=a[1]+min(a[1],a[2]+a[3]);
		if(a[1]==0){
			cout<<0;
			return 0;
		}
		cout<<min(ans1,min(ans2,ans3))<<"\n";
	}
	return 0;
}
<think>我们之前使用了`SolverOptions`中的`IntegerTolerance`参数,但如果在你的Solver版本中未找到此参数,可能是由于以下原因: 1. 不同版本的Excel Solver对VBA接口的支持略有差异 2. 该参数在较新版本中可能被重命名或移除 3. 你的Solver可能不支持整数规划的容差设置 ### 替代解决方案:不使用IntegerTolerance #### 修改后的代码(兼容旧版Solver): ```vba Sub SolveEquipmentProblem_Compatible() SolverReset SolverOk SetCell:="$B$11", MaxMinVal:=2, ValueOf:=0, ByChange:="$B$5:$B$6" ' 添加约束(与之前相同) SolverAdd CellRef:="$B$8", Relation:=3, FormulaText:="$B$2" ' 总盘位 ≥ 需求盘位 SolverAdd CellRef:="$B$9", Relation:=3, FormulaText:="$B$3" ' 总卡数 ≥ 需求卡数 SolverAdd CellRef:="$B$5:$B$6", Relation:=4, FormulaText:="integer" ' 整数约束 SolverAdd CellRef:="$B$5:$B$6", Relation:=3, FormulaText:="0" ' 非负约束 ' 移除了IntegerTolerance设置 ' 只保留线性规划假设(如果问题是非线性的,则不应使用) SolverOptions AssumeLinear:=True ' 执行求解 SolverSolve UserFinish:=True End Sub ``` ### 为什么需要IntegerTolerance? - **作用**:允许整数解有一定百分比偏差(例如1%表示允许0.01的偏差) - **默认值**:通常为5%(即0.05) - **移除影响**:求解会更严格,但可能增加计算时间 ### 兼容性处理建议: 1. **检查Solver版本**: ```vba Sub CheckSolverVersion() MsgBox "Solver版本: " & Application.Solver.Version End Sub ``` 2. **条件设置参数**: ```vba Sub SolveWithCompatibility() ' ... 前面的设置代码 ... On Error Resume Next ' 忽略错误 ' 尝试设置IntegerTolerance(如果支持) SolverOptions IntegerTolerance:=1 On Error GoTo 0 ' 恢复错误处理 SolverSolve UserFinish:=True End Sub ``` 3. **替代加速方法**: ```vba SolverOptions MaxTime:=60, Iterations:=1000, Precision:=0.0001 ``` - `MaxTime`:最长求解时间(秒) - `Iterations`:最大迭代次数 - `Precision`:约束精度(数值越小越精确) ### 完整兼容性代码示例: ```vba Sub RobustSolver() SolverReset SolverOk SetCell:="$B$11", MaxMinVal:=2, ValueOf:=0, ByChange:="$B$5:$B$6" ' 基本约束 SolverAdd "$B$8", 3, "$B$2" ' 盘位约束 SolverAdd "$B$9", 3, "$B$3" ' 卡数约束 SolverAdd "$B$5:$B$6", 4, "integer" ' 整数约束 SolverAdd "$B$5:$B$6", 3, "0" ' 非负约束 ' 兼容性设置 On Error Resume Next ' 新版本参数 SolverOptions AssumeNonNeg:=False ' 已单独设置非负约束 SolverOptions Scaling:=True ' 自动缩放比例 SolverOptions IntegerTolerance:=5 ' 尝试设置5%容差(忽略错误) ' 旧版本参数 SolverOptions MaxTime:=120 ' 最长120秒 SolverOptions Iterations:=5000 ' 最大迭代次数 SolverOptions Precision:=0.000001 ' 约束精度 On Error GoTo 0 ' 求解 SolverSolve UserFinish:=True End Sub ``` ### 常见错误处理: | 错误代码 | 原因 | 解决方案 | |---------|------|---------| | 1004 | Solver未安装 | 启用Solver插件:文件→选项→加载项→转到→勾选Solver | | 438 | 方法或属性不支持 | 移除不支持的`SolverOptions`参数 | | 5 | 无可行解 | 检查约束条件是否矛盾 | ### 如果仍无法解决: 使用VBA调用OpenSolver(免费开源替代品): 1. 下载安装OpenSolver:https://opensolver.org/ 2. 使用示例代码: ```vba Sub RunOpenSolver() ' 需要先引用OpenSolver OpenSolver.RunOpenSolver End Sub ``` §§相关问题§§: 1. 如何通过VBA检查Excel Solver插件是否已安装? 2. 当Solver无法求解时,如何用VBA自动回退到启发式算法? 3. 在Python中如何设置整数规划的容差(如使用PuLP库时)? 4. 如何用VBA读取Solver的结果并生成报告?</think>## 解决 "未找到参数 IntegerTolerance" 错误 当您在 Excel VBA 的 SolverOptions 中遇到 "未找到参数 IntegerTolerance" 错误时,通常是因为您的 Excel 版本不支持此特定参数。不同版本的 Excel Solver 有不同的可用参数集。 ### 解决方案:使用兼容的 SolverOptions 参数 #### 替代方法 1:使用通用优化参数(推荐) ```vba Sub SolveWithCompatibleOptions() SolverReset SolverOk SetCell:="$B$11", MaxMinVal:=2, ValueOf:=0, ByChange:="$B$5:$B$6" ' 添加约束(与之前相同) SolverAdd CellRef:="$B$8", Relation:=3, FormulaText:="$B$2" SolverAdd CellRef:="$B$9", Relation:=3, FormulaText:="$B$3" SolverAdd CellRef:="$B$5:$B$6", Relation:=4, FormulaText:="integer" SolverAdd CellRef:="$B$5:$B$6", Relation:=3, FormulaText:="0" ' 使用兼容的求解选项 SolverOptions _ AssumeLinear:=True, _ ' 声明为线性问题 MaxTime:=60, _ ' 最大求解时间(秒) Iterations:=1000, _ ' 最大迭代次数 Precision:=0.000001 ' 解的精度 SolverSolve UserFinish:=True End Sub ``` #### 替代方法 2:使用特定版本的参数 ```vba Sub SolveWithVersionSpecificOptions() ' ... 前面的设置代码 ... ' 根据 Excel 版本选择参数 Dim excelVersion As Double excelVersion = CDbl(Application.Version) If excelVersion >= 16.0 Then ' Office 2016+ SolverOptions Tolerance:=1, Scaling:=True ElseIf excelVersion >= 15.0 Then ' Office 2013 SolverOptions Convergence:=0.0001, Scaling:=True Else ' Office 2010 及更早版本 SolverOptions Precision:=0.000001, Scaling:=True End If SolverSolve UserFinish:=True End Sub ``` ### 关键参数说明 1. **Precision**: - 控制约束满足的精度 - 值越小,解越精确(但计算时间越长) - 默认值通常为 0.000001 2. **Tolerance** (较新版本): - 整数解的容差百分比 - 替代 IntegerTolerance 的功能 - 例如:Tolerance:=1 表示 1% 容差 3. **MaxTime**: - 最大求解时间(秒) - 防止长时间运行 4. **Iterations**: - 最大迭代次数 - 防止无限循环 ### 完整兼容性解决方案 ```vba Sub RobustSolver() On Error Resume Next ' 忽略不支持的参数错误 SolverReset SolverOk SetCell:="$B$11", MaxMinVal:=2, ValueOf:=0, ByChange:="$B$5:$B$6" ' 添加约束 SolverAdd "$B$8", 3, "$B$2" ' 盘位约束 SolverAdd "$B$9", 3, "$B$3" ' 卡数约束 SolverAdd "$B$5:$B$6", 4, "integer" ' 整数约束 SolverAdd "$B$5:$B$6", 3, "0" ' 非负约束 ' 尝试设置各种可能的容差参数 SolverOptions AssumeLinear:=True SolverOptions Precision:=0.000001 SolverOptions Tolerance:=1 ' 新版本 SolverOptions IntegerTolerance:=1 ' 如果支持则设置 SolverOptions Convergence:=0.01 ' 替代参数 ' 设置求解时间限制 SolverOptions MaxTime:=60, Iterations:=5000 ' 执行求解 SolverSolve UserFinish:=True On Error GoTo 0 ' 恢复错误处理 ' 检查求解状态 If SolverSolve(True) <> 0 Then MsgBox "求解失败,请检查约束条件" End If End Sub ``` ### 为什么 IntegerTolerance 不可用? 1. **版本差异**: - Excel 2010 及更早版本使用 `Precision` - Excel 2013 引入了 `Convergence` - Excel 2016+ 使用 `Tolerance` 和 `IntegerTolerance` 2. **Solver 引擎类型**: - 标准 GRG 非线性引擎不支持整数容差 - 仅当使用 Evolutionary 或 LP 引擎时才可用 3. **替代方案**: ```vba ' 使用更通用的精度控制 SolverOptions Precision:=0.01 ' 相当于 1% 容差 ``` ### 检查可用参数的方法 ```vba Sub ListSolverParameters() Dim paramList As String On Error Resume Next ' 测试各种参数 SolverOptions AssumeLinear:=True If Err.Number = 0 Then paramList = paramList & "AssumeLinear, " Err.Clear SolverOptions IntegerTolerance:=1 If Err.Number = 0 Then paramList = paramList & "IntegerTolerance, " Err.Clear ' 添加其他参数测试... MsgBox "支持的参数: " & Left(paramList, Len(paramList) - 2) End Sub ``` ### 如果所有方法都失败 考虑使用 OpenSolver(免费开源替代品): 1. 下载地址:https://opensolver.org/ 2. 安装后使用: ```vba Sub UseOpenSolver() ' 需要先引用 OpenSolver OpenSolver.Reset OpenSolver.SetObjectiveFunctionCell "$B$11", OpenSolver.Minimise OpenSolver.SetDecisionVariables "$B$5:$B$6" OpenSolver.AddConstraint "$B$8 >= $B$2" OpenSolver.AddConstraint "$B$9 >= $B$3" OpenSolver.SetVariableType "$B$5:$B$6", OpenSolver.VariableType.Integer OpenSolver.Solve End Sub ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值