P1080 [NOIP2012 提高组] 国王游戏 贪心

[NOIP2012 提高组] 国王游戏

传送门

题目描述

恰逢 H 国国庆,国王邀请 n n n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n n n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入格式

第一行包含一个整数 n n n,表示大臣的人数。

第二行包含两个整数 a a a 和 b b b,之间用一个空格隔开,分别表示国王左手和右手上的整数。

接下来 n n n 行,每行包含两个整数 a a a 和 b b b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

输出格式

一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

样例 #1

样例输入 #1

3 
1 1 
2 3 
7 4 
4 6

样例输出 #1

2

提示

【输入输出样例说明】

按 1 1 1、 2 2 2、 3 3 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2;

按 1 1 1、 3 3 3、 2 2 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2;

按 2 2 2、 1 1 1、 3 3 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2;

按 2 2 2、 3 3 3、 1 1 1这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 9 9;

按 3 3 3、 1 1 1、 2 2 2这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2;

按 3 3 3、 2 2 2、 1 1 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 9 9。

因此,奖赏最多的大臣最少获得 2 2 2 个金币,答案输出 2 2 2。

【数据范围】

对于 20 % 20\% 20% 的数据,有 1 ≤ n ≤ 10 , 0 < a , b < 8 1≤ n≤ 10,0 < a,b < 8 1≤n≤10,0<a,b<8;

对于 40 % 40\% 40% 的数据,有 1 ≤ n ≤ 20 , 0 < a , b < 8 1≤ n≤20,0 < a,b < 8 1≤n≤20,0<a,b<8;

对于 60 % 60\% 60% 的数据,有 1 ≤ n ≤ 100 1≤ n≤100 1≤n≤100;

对于 60 % 60\% 60% 的数据,保证答案不超过 1 0 9 10^9 109;

对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 1 , 000 , 0 < a , b < 10000 1 ≤ n ≤1,000,0 < a,b < 10000 1≤n≤1,000,0<a,b<10000。

NOIP 2012 提高组 第一天 第二题

解题思路

  • 考虑对一合法大臣排列,交换i与j(i<j)的位置,就能获得更优解
  • 设 A i A_i Ai= a 1 ⋅ a 2 ⋅ ... ⋅ a i a_1·a_2·...·a_i a1⋅a2⋅...⋅ai
  • 交换前 A n s 1 = M a x ( A i − 1 / b i , A j − 1 / b j ) Ans1=Max(A_{i-1}/b_i,A_{j-1}/b_j) Ans1=Max(Ai−1/bi,Aj−1/bj)
  • 交换后 A n s 2 = M a x ( A i − 1 / b j , A j − 1 ∗ a j / a i / b i ) Ans2=Max(A_{i-1}/b_j,A_{j-1}*a_j/a_i/b_i) Ans2=Max(Ai−1/bj,Aj−1∗aj/ai/bi)
  • 需满足 A n s 1 > A n s 2 Ans1>Ans2 Ans1>Ans2才需交换
    由 A i − 1 / b i < A j − 1 ∗ a j / a i / b i A_{i-1}/b_i < A_{j-1}*a_j/a_i/b_i Ai−1/bi<Aj−1∗aj/ai/bi; A j − 1 / b j > A i − 1 / b j A_{j-1}/b_j > A_{i-1}/b_j Aj−1/bj>Ai−1/bj,可知,若等式成立,则
    • 必然满足 A j − 1 / b j > A j − 1 ∗ a j / a i / b i A_{j-1}/b_j > A_{j-1}*a_j/a_i/b_i Aj−1/bj>Aj−1∗aj/ai/bi
    • 即 a i ⋅ b i > a j ⋅ b j a_i·b_i>a_j·b_j ai⋅bi>aj⋅bj
    • 以此排序即可获得最优排列顺序

(什么证完了?还不懂?戳我

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 1000 + 5;
int n, A, B;
struct project {
	int a, b;
} hands[Maxn];
int sum[Maxn], tmp[Maxn], p[Maxn], len2, len1, m, P;
inline bool cmp(project A, project B) {
	if (A.a * A.b == B.a * B.b) {
		return A.b < B.b;
	}
	return A.a * A.b < B.a * B.b;
}
inline bool Max() {
	int i, j;
	i = j = 1;
	while (p[i] == 0 && i <= len2) {
		i++;
	}
	while (tmp[j] == 0 && j <= len1) {
		j++;
	}
	if (len2 - i + 1 > len1 - j + 1) {
		return 0;
	}
	if (len2 - i + 1 < len1 - j + 1) {
		return 1;
	}
	while (i <= len2 && j <= len1) {
		if (p[i] < tmp[j]) {
			return 1;
		}
		if (p[i] > tmp[j]) {
			return 0;
		}
		i++;
		j++;
	}
	return 0;
}
inline void mul(int d) {
	for (int i = 1; i <= m; i++) {
		sum[i] *= hands[d].a;
	}
	for (int i = 1; i <= m; i++) {
		sum[i + 1] += sum[i] / 10000;
		sum[i] %= 10000;
	}
	if (sum[m + 1] != 0) {
		m++;
	}
}
inline void div(int d) {
	memset(tmp, 0, sizeof(tmp));
	len1 = 1;
	while (m > 0 && sum[m] == 0) {
		m--;
	}
	P = 0;
	bool flag = 0;
	for (int i = m; i >= 1; i--) {
		P = P * 10000 + sum[i];
		tmp[++len1] = P / hands[d].b;
		if (tmp[len1] == 0 && !flag) {
			len1--;
		} else {
			flag = 1;
		}
		P %= hands[d].b;
	}
}
inline void work() {
	cin >> n >> A >> B;
	for (int i = 1; i <= n; i++) {
		cin >> hands[i].a >> hands[i].b;
	}
	sort(hands + 1, hands + n + 1, cmp);
	m = 1;
	sum[1] = A;
	for (int i = 1; i <= n; i++) {
		div(i);
		if (Max()) {
			len2 = len1;
			memcpy(p, tmp, sizeof(tmp));
		}
		mul(i);
	}
	int i = 0;
	while (i <= len2 && p[i] == 0) {
		i++;
	}
	cout << p[i];
	i++;
	for (; i <= len2; i++) {
		if (0 <= p[i] && p[i] <= 9) {
			cout << "000" << p[i];
		} else if (10 <= p[i] && p[i] <= 99) {
			cout << "00" << p[i];
		} else if (100 <= p[i] && p[i] <= 999) {
			cout << "0" << p[i];
		} else {
			cout << p[i];
		}
	}
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	work();
	return 0;
}

想要提升实力?看这里

相关推荐
福大大架构师每日一题21 分钟前
文心一言 VS 讯飞星火 VS chatgpt (396)-- 算法导论25.2 1题
算法·文心一言
EterNity_TiMe_36 分钟前
【论文复现】(CLIP)文本也能和图像配对
python·学习·算法·性能优化·数据分析·clip
机器学习之心1 小时前
一区北方苍鹰算法优化+创新改进Transformer!NGO-Transformer-LSTM多变量回归预测
算法·lstm·transformer·北方苍鹰算法优化·多变量回归预测·ngo-transformer
yyt_cdeyyds1 小时前
FIFO和LRU算法实现操作系统中主存管理
算法
daiyang123...1 小时前
测试岗位应该学什么
数据结构
alphaTao1 小时前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode
kitesxian2 小时前
Leetcode448. 找到所有数组中消失的数字(HOT100)+Leetcode139. 单词拆分(HOT100)
数据结构·算法·leetcode
VertexGeek2 小时前
Rust学习(八):异常处理和宏编程:
学习·算法·rust
石小石Orz2 小时前
Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~
javascript·人工智能·算法
jiao_mrswang3 小时前
leetcode-18-四数之和
算法·leetcode·职场和发展