P1080 [NOIP2012 提高组] 国王游戏(贪心+高精度(包含高/低模板))

确定一种排列方式满足题目要求。

首先对于两个大臣分析(联想到排序算法中cmp比较函数,也是按照某种规则比较两个量,这里我们也分析两个),若1和2要交换,需满足max{a0/b1, (a0*a1)/b2} > max{a0/b2, (a0*a2)/b1},同时约去a0, max{1/b1, a1/b2} > max{1/b2, a2/b1},注意到1/b1 <= a2/b1,a1/b2 >= 1/b2。

只需满足a1/b2 > a2/b1, 即a1*b1 > a2*b2。所以我们按照a*b升序排列。

套上高精度乘法, 高精/低精除法模板。

#include <bits/stdc++.h>
using namespace std;
int n;
struct node {
	int a, b;
	char cnta[10005];//a前缀积(除当前a) 
	char ca[1005];//a字符 
	char ans[10005];//获得金币数 
	//字符均为倒序,用char类型便于直接得到len
	int lans; 
}mi[1005];//minister
bool cmp(node x, node y) {//按a*b升序排列 
	return x.a * x.b < y.a * y.b;
}
bool cmp2(node x, node y) {
	if (x.lans != y.lans) return x.lans > y.lans;
	else {
		for (int i = 0; i <= x.lans; i ++)
			if (x.ans[i] == y.ans[i]) continue;
			else return x.ans[i] > y.ans[i];
	}
	return 1;
}
void trans(int a, char b[]) {
	int p = 0;
	while (a) {
		b[p ++] = a % 10 + '0';
		a /= 10;
	}
	b[p] = '\0';//结束 
}
void mul(char a[], char b[], char c[]) {//高乘 
	int la = strlen(a), lb = strlen(b);
	int x[10005] = {0}, y[10005] = {0}, z[10005] = {0};
	for (int i = 0; i < la; i ++) x[i + 1] = a[i] - '0';
	for (int i = 0; i < lb; i ++) y[i + 1] = b[i] - '0';
	for (int i = 1; i <= la; i ++) 
		for (int j = 1; j <= lb; j ++)
			z[i + j - 1] += x[i] * y[j];
	int len = la + lb;
	for (int i = 1; i <= len; i ++) {
		z[i + 1] += z[i] / 10;
		z[i] %= 10;
	}
	while (!z[len]) len --;
	for (int i = 1; i <= len; i ++)
		c[i - 1] = z[i] + '0';
}
void div(char a[], int b, char c[]) {//高精/低精 
	//不需要逆序储存
	int re = 0;//记录余数 
	int x[10005] = {0}, z[10005] = {0};
	int la = strlen(a);
	for (int i = 0; i < la; i ++) x[la - i] = a[i] - '0';
	for (int i = 1; i <= la; i ++) {//模拟竖式除法 
		z[i] = (re * 10 + x[i]) / b;
		re = (re * 10 + x[i]) % b;
	}
	int p = 1;
	while (z[p] == 0 && p < la) p ++;
	int p1 = 0;
	for (int i = p; i <= la; i ++)
		c[p1 ++] = z[i] + '0';
	c[p1] = '\0';
}
int main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n; cin >> mi[0].a >> mi[0].b;
	for (int i = 1; i <= n; i ++) cin >> mi[i].a >> mi[i].b;
	sort(mi + 1, mi + n + 1, cmp);
	trans(mi[0].a, mi[0].ca);
	mi[0].cnta[0] = '1', mi[0].cnta[1] = '\0';
	for (int i = 1; i <= n; i ++) {
		trans(mi[i].a, mi[i].ca);
		mul(mi[i - 1].cnta, mi[i - 1].ca, mi[i].cnta);//得到前缀积 
	}
	for (int i = 1; i <= n; i ++) {
		div(mi[i].cnta, mi[i].b, mi[i].ans);
		mi[i].lans = strlen(mi[i].ans);
	}
	int ans = 1;
	for (int i = 2; i <= n; i ++)
		if (!cmp2(mi[ans], mi[i])) ans = i;
	for (int i = 0; i < mi[ans].lans; i ++)
		cout << mi[ans].ans[i];
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值