CF10E Greedy Change 题解
http://codeforces.com/problemset/problem/10/E
题意
给出货币系统 满足 ,请找到最小的 使贪心算法需要的货币数目比最优解多。
贪心算法:每次取最大的不超过 的货币。
题解
把 的货币系统表示记作向量 ,即 。
令向量 为表示 字典序最大的最优解, 为贪心解(是字典序最大的表示)。
这样限制可以直接比较两个向量。开始推性质(下面的比较都是字典序):
-
-
的子集是最优的表示, 的子集是贪心表示。
这些都由定义易得。
定义 为最小的解,这样取一个子集之后 是相等的,可以找一些必要条件:
- 非零位无交。
如果 的第 位均大于 , 是比 更优的解,矛盾。
设 为 的最低和最高非零位。
- 前 位为 。
前 位为 前 位为 前 位为 。
推论:。
- 在前 位有非零位。
第 位一定是 ,如果前 位也全部是 ,那么字典序就小于 了,与定义矛盾。
推论:。
现在整理一下限制,因为 的数量不多,想要建立和 的关系:
发现把向量第 位加 仍是符合定义的。
对于 考虑贪心过程是显然的。
对于 , 是 的子集,至少需要再某一位加 ,必然是第 位。
于是得到 。
从另一个限制出发:
本来 字典序大于 ,第 位减 后就小于等于了。
首先它们 位之前相等。由于 第 位之后都是 ,所以 第 位恰好为 第 为加 。
现在可以枚举 , check,时间复杂度 。
代码:
#include <bits/stdc++.h>
using namespace std;
const int inf=2e9;
int main(){
int n,ans=inf;
scanf("%d",&n);
vector<int> c(n);
for(int&x:c) scanf("%d",&x);
auto val=[&](int x){
int res=0;
for(int v:c) res+=x/v,x%=v;
return res;
};
for(int i=1;i<n;i++){
int s=c[i-1]-1,x=s,m=0;
for(int j=i;j<n;j++){
m+=x/c[j];x%=c[j];
if(m+1<val(s-x+c[j])) ans=min(ans,s-x+c[j]);
}
}
printf("%d\n",ans==inf?-1:ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
2021-11-02 CF1246E To Make 1 题解