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;
}

想要提升实力?看这里

相关推荐
青椒大仙KI11几秒前
24/9/19 算法笔记 kaggle BankChurn数据分类
笔记·算法·分类
^^为欢几何^^4 分钟前
lodash中_.difference如何过滤数组
javascript·数据结构·算法
豆浩宇4 分钟前
Halcon OCR检测 免训练版
c++·人工智能·opencv·算法·计算机视觉·ocr
浅念同学20 分钟前
算法.图论-并查集上
java·算法·图论
何不遗憾呢28 分钟前
每日刷题(算法)
算法
立志成为coding大牛的菜鸟.33 分钟前
力扣1143-最长公共子序列(Java详细题解)
java·算法·leetcode
鱼跃鹰飞33 分钟前
Leetcode面试经典150题-130.被围绕的区域
java·算法·leetcode·面试·职场和发展·深度优先
liangbm339 分钟前
数学建模笔记——动态规划
笔记·python·算法·数学建模·动态规划·背包问题·优化问题
潮汐退涨月冷风霜44 分钟前
机器学习之非监督学习(四)K-means 聚类算法
学习·算法·机器学习
B站计算机毕业设计超人1 小时前
计算机毕业设计Python+Flask微博情感分析 微博舆情预测 微博爬虫 微博大数据 舆情分析系统 大数据毕业设计 NLP文本分类 机器学习 深度学习 AI
爬虫·python·深度学习·算法·机器学习·自然语言处理·数据可视化