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

想要提升实力?看这里

相关推荐
XH华3 小时前
初识C语言之二维数组(下)
c语言·算法
南宫生4 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
不想当程序猿_4 小时前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯
落魄君子4 小时前
GA-BP分类-遗传算法(Genetic Algorithm)和反向传播算法(Backpropagation)
算法·分类·数据挖掘
菜鸡中的奋斗鸡→挣扎鸡4 小时前
滑动窗口 + 算法复习
数据结构·算法
Lenyiin4 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
郭wes代码4 小时前
Cmd命令大全(万字详细版)
python·算法·小程序
scan7245 小时前
LILAC采样算法
人工智能·算法·机器学习
菌菌的快乐生活5 小时前
理解支持向量机
算法·机器学习·支持向量机
大山同学5 小时前
第三章线性判别函数(二)
线性代数·算法·机器学习