noip2012 国王游戏
1198 国王游戏
2012年NOIP全国联赛提高组
恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
第一行包含一个整数 n,表示大臣的人数。
第二行包含两个整数a和b,之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来n行,每行包含两个整数a和b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的
金币数。
3
1 1
2 3
7 4
4 6
2
【输入输出样例说明】
按 1、2、3号大臣这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 1、3、2这样排列队伍,获得奖赏最多的大臣所获得金币数为2;
按 2、1、3这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 2、3、1这样排列队伍,获得奖赏最多的大臣所获得金币数为 9;
按 3、1、2这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 3、2、1这样排列队伍,获得奖赏最多的大臣所获得金币数为 9。
因此,奖赏最多的大臣最少获得 2 个金币,答案输出 2。
【数据范围】
对于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 ≤1,000,0 < a、b < 10000。
分析:最大值最小,难道是二分,但是每次二分一个值都要搜全排列,超时妥妥的.因为求最大值最小,似乎是贪心,贪心就意味着排序,怎么排序呢?假设这个最大值是已经定好的,那么我们就要让每一个数尽量的小,所以i排在j前面的前提是t * a[i] / b[j] < t * a[j] / b[i],其中t是前i-1个大臣左手的乘积,a和b分别是左右手上的数,化简得a[i] * b[i] < a[j] * b[j].保证让后面的数小.注意看数据范围:保证答案不超过10^9,这要引起我们的警觉,那么肯定有40%的数据会超过它,这个时候就要用到高精度了!这个高精度非常麻烦,平生最讨厌高精度的难题.那么答案是什么呢?不要一连串的乘起来了,排序并不是按照所得金币数来排的,不能保证最后一个大臣得到的金币数最多,所以要枚举寻找最大值.另外做这类贪心+排序的题如果看不出来怎么排,随便取两个相邻的数捣鼓捣鼓就出来了.
这是60分代码:(写炸了)
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 10010, maxm = 50000, inf = 100000000; int n,lens, ans[maxm], sum[maxm], t[maxm],lena,lent; struct node { int a, b; }s[maxn]; bool cmp(node x, node y) { return x.a * x.b < y.a * y.b; } void cheng(int x) { int jinwei = 0; for (int i = 0; i < lens; i++) { sum[i] = sum[i] * x + jinwei; jinwei = sum[i] / inf; sum[i] %= inf; } while (jinwei > 0) { sum[lens++] = jinwei % inf; jinwei /= inf; } } void chu(int x) { int buwei = 0; for (int i = lens - 1; i >= 0; i--) { buwei = buwei * inf + sum[i]; t[i] = buwei / x; buwei -= x * t[i]; } for (int i = lens - 1; i >= 0; i--) if (t[i] > 0) { lent = i + 1; break; } } void fuzhi() { for (int i = lent - 1; i >= 0; i--) ans[i] = t[i]; } void gengxin() { if (lent > lena) { fuzhi(); lena = lent; } else if (lent == lena) for (int i = lent - 1; i >= 0; i--) { if (t[i] > ans[i]) { fuzhi(); break; } else if (t[i] < ans[i]) break; } } void huifu(int x) { int h = inf; while (h >= 10) { h /= 10; if (x < h) printf("0"); } } int main() { scanf("%d", &n); for (int i = 0; i <= n; i++) scanf("%d%d", &s[i].a, &s[i].b); sort(s + 1, s + n + 1, cmp); sum[0] = 1; lens = 1; for (int i = 0; i < n; i++) { cheng(s[i].a); chu(s[i + 1].b); gengxin(); } for (int i = lena - 1; i >= 0; i--) { if (i != lena - 1) huifu(ans[i]); printf("%d", ans[i]); } printf("\n"); return 0; }
AC代码写不出来,借用一下codevs一位大神的代码:
#include<stdio.h> #include<algorithm> using namespace std; int n;//丞相人数 int ans[5000];//答案 int tt[5000]; int len;//ans长度 int maxp; int maxans[5000]; void gx(int a)//高精乘 { int t[5000]; t[1] = 0; for (int i = 1;i <= len || (i>len&&t[i] != 0);i++) { ans[i] *= a; ans[i] += t[i]; t[i + 1] = ans[i] / 10; ans[i] %= 10; ans[0] = i; } len = ans[0]; } void gc(int b)//高精除 { bool shit = 0; for (int i = len;i >= 2;i--) { ans[i - 1] += (ans[i] % b) * 10; ans[i] /= b; if (!shit) { if (!ans[i])len--; else shit = 1; } } ans[1] /= b; ans[0] = len; } void ggc(int b)//高精除 { bool shit = 0; for (int i = tt[0];i >= 2;i--) { tt[i - 1] += (tt[i] % b) * 10; tt[i] /= b; if (!shit) { if (!tt[i])tt[0]--; else shit = 1; } } tt[1] /= b; } struct person//每个人的信息 { int a, b, c; }p[100005]; bool cmp(person x, person y)//判断优劣 { return x.c<y.c; } void ready()//初始化 { maxans[0] = 1; maxans[1] = -1; ans[1] = p[0].a; ans[0] = len = 1; } void gcmp(int a[], int b[]) { if (a[0]>b[0]) { for (int i = a[0];i >= 0;i--) maxans[i] = a[i]; return; } else if (a[0]<b[0])return; else { for (int j = ans[0];j >= 1;j--) { if (a[j]>b[j]) { for (int i = a[0];i >= 0;i--) maxans[i] = a[i]; return; } else if (a[j]<b[j])return; } } return; } int main() { scanf("%d", &n); for (int i = 0;i <= n;i++) { scanf("%d%d", &p[i].a, &p[i].b); p[i].c = p[i].a*p[i].b; } sort(p + 1, p + 1 + n, cmp); // for(int i=1;i<=n;i++) // printf("%d %d %d\n",p[i].a,p[i].b,p[i].c); ready(); for (int i = 1;i <= n;i++) { for (int j = tt[0];j >= 0;j--) tt[j] = 0; for (int j = 0;j <= ans[0];j++) tt[j] = ans[j]; ggc(p[i].b); gcmp(tt, maxans); gx(p[i].a); } for (int i = maxans[0];i >= 1;i--) printf("%d", maxans[i]); return 0; }