noip2012国王游戏

【题目描述】

恰逢 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 < 10^5。

看起来很难求;
分析这道题的赏金的决定方式,可发现这是道贪心
对于第i个点和第i+1个点。左手为a[i]和a[i+1],右手为b[i]和b[i+1]。金币数为w[i]和w[i+1]。
P[i]=a[1]*a[2]*a[3]*...*a[i]
可得:

w[i]=P[i-1]/b[i];

w[i+1]=P[i]/b[i+1];

又P[i]=P[i-1]*a[i]
那么 w[i+1]=P[i-1]*a[i]/b[i+1]=w[i]*a[i]*b[i]/b[i-1]

不难看出,在这个相邻的二元组中,前面的数不受后面的影响,而后面的金币数决定于w[i],a[i],b[i]。

推广到整个排队方案,前面的金币数和a[i],b[i]都会影响后面的答案。贪心原则便出来了:

按a[i]*b[i]为关键字从小到大排序,相同的顺序无所谓。最后再扫一遍,算出答案即可。

n<=1000,a,b<=10^5

所以要写高精度

代码如下:


   
   
  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <iostream>
  5. using namespace std;
  6. struct BIG{
  7. int C[6000];
  8. int len;
  9. BIG(){
  10. memset(C,0,sizeof(C));
  11. len=0;
  12. };
  13. bool operator > (const BIG& c) const {
  14. if(len!=c.len)
  15. return len>c.len;
  16. for(int i=len;i>=1;i--)
  17. if(C[i]!=c.C[i])
  18. return C[i]>c.C[i];
  19. return false;
  20. }
  21. BIG operator * (const BIG& b) const {
  22. BIG c;
  23. int x;
  24. for(int i=1;i<=len;i++){
  25. x=0;
  26. for(int j=1;j<=b.len;j++){
  27. c.C[i+j-1]+=b.C[j]*C[i]+x;
  28. x=c.C[i+j-1]/10;
  29. c.C[i+j-1]%=10;
  30. }
  31. c.C[i+b.len]=x;
  32. }
  33. c.len=5000;
  34. while(c.C[c.len]==0&&c.len>1)
  35. c.len--;
  36. return c;
  37. }
  38. BIG operator /(const int& b)const{
  39. BIG c;
  40. c.len=5000;
  41. long long d=0;
  42. for(int i=len;i>=1;i--){
  43. d=d*10+C[i];
  44. c.C[i]=d/b;
  45. d%=b;
  46. }
  47. while(c.C[c.len]==0&&c.len>1)
  48. c.len--;
  49. return c;
  50. }
  51. };
  52. struct T{
  53. int L,R,kt;
  54. bool operator < (const T& c) const {
  55. return kt<c.kt;
  56. }
  57. }A[1001];
  58. BIG tran(int b){
  59. BIG c;
  60. int i=1;
  61. while(b>0){
  62. c.C[i++]=b%10;
  63. b/=10;
  64. }
  65. c.len=i-1;
  66. return c;
  67. }
  68. int main(){
  69. freopen("kinggame.in","r",stdin);
  70. freopen("kinggame.out","w",stdout);
  71. int x,y;
  72. int n;
  73. scanf("%d",&n);
  74. scanf("%d %d",&x,&y);
  75. BIG num=tran(x);
  76. for(int i=1;i<=n;i++){
  77. scanf("%d %d",&A[i].L,&A[i].R);
  78. A[i].kt=A[i].L*A[i].R;
  79. }
  80. sort(A+1,A+n+1);
  81. BIG maxx;
  82. for(int i=1;i<=n;i++){
  83. if(num/A[i].R>maxx)
  84. maxx=(num/A[i].R);
  85. num=num*tran(A[i].L);
  86. }
  87. for(int i=maxx.len;i>=1;i--)
  88. printf("%d",maxx.C[i]);
  89. printf("\n");
  90. return 0;
  91. }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值