洛谷 普及组 P1080 国王游戏

题目描述

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

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

输入格式

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

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

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

输出格式

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

数据范围

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

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

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

对于 60%的数据,保证答案不超过 10^{9}

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

输入输出样例

  输入

3 
1 1 
2 3 
7 4 
4 6

  输出

2

思路

▶拿小A作比如,小A的奖金是他之前所有人的左手数除以小A自己右手上的数。由于要计算的是最高奖金,我们可以知道当小A站在最后面时奖金数目最大,同理,每个人站在最后面时奖金数目最大。而我们最终要求的就是最高奖金的最小值,所以只需求每个人站在最后面时的奖金数,取最小值就行。

▶每个人站在最后面时,奖金都是一个算法,所有人(包括最后一人)左手数÷最后一人的左手数÷最后一人的右手数

▶题目难在高精度算法,高精度算法一般用字符串接收参与运算的数字,然后转换成int变量存放在整型数组,逐个元素计算。

   自学高精度乘法可参考:https://blog.csdn.net/qiminghang/article/details/81046179,言简意赅。

   高精度除法可参考:https://blog.csdn.net/qq_41993986/article/details/80022796 里的按位相除法,也很容易理解。

#include<iostream>
#include<string.h>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 100000
struct Mr{
	string l, r;
}mr[1000];
int main()
{
	int n;
	string kl, kr, tot; //国王左手,国王右手,所有人左手数
	cin >> n >> kl >> kr;
	string stra = kl, strb, strc = ""; //高精度算法变量
	int lena = stra.length(), lenb, lenc;
	
	for(int i = 0; i < n; i++){ 
		int a[maxn]={0}, b[maxn]={0}, c[maxn]={0};
		cin >> mr[i].l >> mr[i].r;
		if(i == 0){
			strb = mr[i].l;
			lenb = strb.length();
		}else{
			stra = strc; lena = stra.length();
			strb = mr[i].l; lenb = strb.length();
			strc = "";
		}
		for(int j = 0; j < lena; j++) a[lena-j-1] = stra[j]-48;
		for(int j = 0; j < lenb; j++) b[lenb-j-1] = strb[j]-48;
		for(int j = 0; j < lena; j++){    //高精度乘法核心
			int r = 0; // 进位 
			for(int k = 0; k < lenb; k++){
				c[j+k] = a[j]*b[k] + r + c[j+k];
				r = c[j+k] / 10;
				c[j+k] %= 10;
			}
			c[lenb+j] = r;
		}
		lenc = lena + lenb;
		while(c[lenc]==0 && lenc>0) lenc--; //最高位为0则退位
		for(int j = lenc; j >= 0; j--)
			strc += char(c[j] + 48);
	}
	string max = strc; //初始化max
	tot = strc; //得到KING和大臣的左手数乘积
	for(int i = 0; i < n; i++){
		stra = tot; lena = stra.length(); //总乘积(被除数)
		strb = mr[i].l; lenb = strb.length();
		strc = "";
		int intl = 0, intr = 0;
		for(int j = 0; j < lenb; j++) intl += (strb[j]-48)*pow(10, lenb-1-j);
		strb = mr[i].r; lenb = strb.length();
		for(int j = 0; j < lenb; j++) intr += (strb[j]-48)*pow(10, lenb-1-j);
		int a[maxn]={0}, b[maxn]={0}, c[maxn]={0};
		int r = 0;
		for(int j = 0; j < lena; j++) a[j] = stra[j]-48;
		for(int j = 0; j < lena; j++){    //高精度除法核心
			c[j] = (r * 10 + a[j]) / (intl * intr);
			r = (r * 10 + a[j]) % (intl * intr);
		}
		lenc = 0;
		while(c[lenc]==0 && lenc < lena) lenc++;
		for(int j = lenc; j < lena; j++){
			strc += char(c[j] + 48);
		}
		if(strc == "") strc = "1";
		if(strc.length() < max.length()) max = strc; //当前字符串长度更小,说明最小值可更新
		else if(strc.length() == max.length() && strc < max) max = strc; //字符串的大小比较是按字典序比较的,若长度一样但max字典序大于strc,则更新max
	}
	cout << max << endl;
	return 0;
} 
发布了13 篇原创文章 · 获赞 20 · 访问量 9382

猜你喜欢

转载自blog.csdn.net/qq_45542674/article/details/104281294
今日推荐