2018-7-8 ACM 刷题日记

本文解析了Codeforces两个经典题目1004B与1003D的解题思路及核心代码。对于1004B,通过A、B花交替摆放实现区间价值最大化;1003D则采用贪心算法,从大面值硬币开始选择以最少数量组合成目标价格。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<Codeforces 1004B>

题意:

有n个花盆,放两种花A,B,有m个区间,每个区间的价值是:A花个数 * B花个数。问怎么摆放花让所有区间的价值和最大。

思路:

设每段区间 A 花有 a 个,B 花有 b 个,根据均值不等式,当 a * b 取最大值时,当且仅当 a == b。所以要求每段区间内 a == b即可。所以只需要将A、B交替摆放,就能让每段区间的A花个数等于B花个数。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxx = 1e3 + 98;
int n, m;
int l, r;

int main() {
	cin >> n >> m;
	for(int i = 1; i <= m; i++) cin >> l >> r;
	for(int i = 1; i <= n; i++) {
		if(i & 1) cout << 1;
		else cout << 0;
	}
	cout << endl;
}


<Codeforces 1003D>

题意:

有 m 个具有某些面值的硬币,有 q 个查询,代表 q 个价格,问恰好组成这 q 个价格所需最少硬币数是多少,没有答案打印-1。

思路:

这题就是个贪心,从大往小贪,开一个map对每个面值都记录一下出现次数,然后

ans的累加有两种方式,比如说碰到面值x,那么要构成我当前的m(价格)值,第一种就是需要(m / x)个硬币,第二种就是需要mp[x]个硬币,所以贪心就,每次都取两者较小的那个即可。核心代码如下:

for(ll i = Inf; i >= 1; i >>= 1) {
			ll tmp = min(mp[i], m / i);
			ans += tmp;
			m -= tmp * i;
		}

为什么每次取两者较小值呢,首先就像我之前说的,肯定面值越大的优先,就是从大往小进行贪心,当我遇到面值x,我最多能提供mp[x]个x,如果说我当前 m / x 比 mp[x] 多,显然是提供 m / x个最好,但是我只能提供 mp[x]个,我也很无奈,所以我只能选mp[x]个;如果说 m / x 比 mp[x]要小,那就意味着,我x本来就最好需要 m / x个,你却有较多的 mp[x]个,那我肯定选最优的m / x个,mp[x]多出的那些没用了,综上取两者较小者。

然后每次让价值m减掉当前硬币面值乘需要个数即可,如果m减不到0,就打印-1,否则打印ans。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll Inf = 1 << 30;
const int maxx = 2e5 + 7;
map <ll, ll> mp;
ll n, q;
ll a[maxx];
ll m, ans;

int main() {
	cin >> n >> q;
	mp.clear();
	for(ll i = 1; i <= n; i++) {
		cin >> a[i];
		mp[a[i]]++;
	}
	while(q--) {
		cin >> m;
		ans = 0;
		for(ll i = Inf; i >= 1; i >>= 1) {
			ll tmp = min(mp[i], m / i);
			ans += tmp;
			m -= tmp * i;
		}
		if(m) cout << "-1" << endl;
		else cout << ans << endl;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值