- 题解
P2001硬币的面值
- 2023-10-1 16:58:28 @
发题解只是为了让大家明白这题咋做,请不要抄题解,我会定期查看,作弊者我将会报告**管理员
其实这道题就按照题面意思直接模拟一下就好喇!
很显然如果给定硬币的最小值大于1则输出"No answer!!!"因为这样子就无法取到1这个面值了。
先证明一下这一点:如果目前状态可取前 x价格,且当前取了一个面额为 a的硬币,要想构成前 x+a的所有价格,必须仅当 x≥a−1 时成立--->
证:若 x<a−1, 则我们取最小的 x+1,它必须由 x+1−a得到,而 x<a−1,故 x+1−a<0,由于不存在小于0的状态,故原命题成立。
假设当前状态,前 i 种硬币已经用最小的硬币数 ans 构成最大的可行价格 tot ,那么如果当前 tot≥a[i]+1−1,那么就可以直接 i++;否则累加,使 tot=tot+a[i] 至 tot≥a[i]+1−1 , 同时每次 ans ++ 。因为我们在每一步都满足 tot≥a[i]+1−1 , 所以每次i++ 时,我们都可以放心操作当前的 tot+a[i] 操作。特别的,当 i 等于1时,如果tot(=0)<a[1]−1 , 即 a[1]>1时,不能满足条件,因而无答案,这里解释了第二段的显然结论。
关于这个累加,由于数据范围很大,我们很容易被卡(如都是1),所以我们先算出 tot 加上多少个a[i] 才能大于等于 a[i]+1,即个数 k=(a[i]+1−2−tot)÷a[i]+1 ,再 tot=tot+k*a[i],ans=ans+k, 用 O(1)的时间解决了问题。同时我们把 ans+1 赋值为 m , 助于判停。
最后注意一点:如果 tot 刚好等于 m−1 ,并结束了循环,此时我们要在循环外输出ans+1 , 以应对此特殊情况。
下面我来贴一下代码--->
#include <bits/stdc++.h>
using namespace std;
long long n, m, a[2000005], ans, tot;
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + n + 1);
if(a[1] != 1) {
cout << "No answer!!!";
return 0;
}
a[n + 1] = m;
for(int i = 1; i <= n; i++){
if(tot < a[i + 1] - 1){
long long k = (a[i + 1] - 2 - tot) / a[i] + 1;
tot += a[i] * k;a
ans += k;
if(tot >= m){
cout<< ans;
return 0;
}
}
}
cout << ans+1;
return 0;
}
2 条评论
-
一只懒馒头 (李奕樊) LV 7 MOD @ 2023-10-1 21:37:43
-
2023-10-1 20:53:12@
建议代码高亢化一下
- 1