发题解只是为了让大家明白这题咋做,请不要抄题解,我会定期查看,作弊者我将会报告**管理员

其实这道题就按照题面意思直接模拟一下就好喇!

很显然如果给定硬币的最小值大于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 条评论

  • 1