「noip2012」国王游戏

Problem description

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

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

Input format 

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

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

Output format

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

Algorithm design

贪心算法

Problem analysis

直接模拟最多采用全排列+记忆化,效率极低,算法很明显是贪心

贪心可以说是目前最难的一个模块了,因为要考验最优解子结构分析

一开始直接想全局放置的方式,想破头也没有想出来

老师说对于线性贪心可以先考虑两两之间的关系,就取相邻两个大臣突破

很容易发现:

令臣a在臣b前,设之前乘积为S,则臣a收益S/ra,臣b收益S*la/rb

反之,臣a收益S*lb/ra,臣b收益S/rb

通分一下,情况1为max(rb,la*ra),情况2为max(ra,lb*rb)

分情况讨论:

(1)la*ra>rb,lb*rb>ra,则li*ri的大小决定了位置(越大越后)

(2)la*ra<rb,因为lb>=1,所以lb*rb>la*ra,且b应该放在a后,不悖结论1

(3)lb*rb<ra,因为la>=1,所以la*ra>lb*rb,且a应该放在b后,不悖结论1

故结论1成立,li*ri越大的臣子越靠后可以使解最优,则进行以li*ri为关键字的排序即可

排序完之后,必定保证金币数从小到大递增,且最后一人为最小的最大值

用这个算法仅过了60,不难发现,数据达到10000时金币可能为10000^10000

这是一个非常庞大的数字,所以想到高精度乘法,除法

码完高精度成绩没有丝毫改观,调试后发现是重载运算符数组开小了,由前面的结论得,至少要开到40000的空间,当不小心开成400000的时候,程序会超时最后这个代码还是90分的,原因是此贪心法则只能保证结果最小,而非最后臣子为最大值,所以ans应该中途更新

Source code

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 struct bign 
  6 {
  7     int len,num[40010];
  8     void clean()
  9     {
 10         while(len>1&&!num[len-1]) 
 11             len--; 
 12     }
 13     bign operator =(string st)
 14     {
 15         memset(num,0,sizeof(num));
 16         len=st.size();
 17         for(int i=0;i<len;i++)
 18             num[i]=st[len-i-1]-'0';
 19         return *this;
 20     }
 21     bign operator =(bign n)
 22     {
 23         memset(num,0,sizeof(num));
 24         len=n.len;
 25         for(int i=0;i<len;i++)
 26             num[i]=n.num[i];
 27         return *this;
 28     }
 29     bign operator +(bign n)
 30     {
 31         bign ans;
 32         memset(ans.num,0,sizeof(ans.num));
 33         ans.len=max(len,n.len);
 34         int accu=0;
 35         for(int i=0;i<ans.len;i++)
 36         {
 37             int res=num[i]+n.num[i]+accu;
 38             ans.num[i]=res%10;
 39             accu=res/10;
 40         }
 41         if(accu)ans.num[ans.len++]=accu;
 42         return ans;
 43     }
 44     bign operator +=(bign n)
 45     {
 46         *this=*this+n;
 47         return *this;
 48     }
 49     bign operator *(int n)
 50     {
 51         bign ans;
 52         memset(ans.num,0,sizeof(ans.num));
 53         ans.len=len;
 54         for(int i=0;i<ans.len;i++)
 55             ans.num[i]=num[i]*n;
 56         int accu=0;
 57         for(int i=0;i<ans.len;i++)
 58         {
 59             ans.num[i]+=accu;
 60             accu=ans.num[i]/10;
 61             ans.num[i]%=10;
 62         }
 63         while(accu)ans.num[ans.len++]=accu%10,accu/=10;
 64         ans.clean();
 65         return ans;
 66     }
 67     bign operator *=(int n)
 68     {
 69         *this=*this*n;
 70         clean();
 71         return *this;
 72     }
 73     bign operator /(int n)
 74     {
 75         bign ans;
 76         memset(ans.num,0,sizeof(ans.num));
 77         ans.len=len;
 78         int res=0;
 79         for(int i=ans.len-1;i>=0;i--)
 80         {
 81             res=res*10+num[i];
 82             ans.num[i]=res/n;
 83             res%=n;
 84         }
 85         while(ans.num[ans.len-1]==0&&ans.len>1)ans.len--;
 86         ans.clean();
 87         return ans;
 88     }
 89     bign operator /=(int n)
 90     {
 91         *this=*this/n;
 92         clean();
 93         return *this;
 94     }
 95     bool operator <(bign n)
 96     {
 97         if(n.len>len)return 1;
 98         if(n.len<len)return 0;
 99         for(int i=len-1;i>=0;i--)
100             if(num[i]<n.num[i])
101                 return 1;
102             else if(num[i]>n.num[i])
103                 return 0;
104         return 0;
105     }
106     friend ostream& operator <<(ostream& out ,bign n)
107     {
108         for(int i=n.len-1;i>=0;i--)
109             out<<n.num[i];
110         return out;
111     }
112 };
113 
114 int n;
115 bign res,ans;
116 
117 struct node
118 {
119     int l,r;
120 }hand[10010];
121 
122 bool cmp(node p,node q)
123 {
124     if(p.l*p.r==q.l*q.r)return p.l<q.l;
125     return p.l*p.r<q.l*q.r;
126 }
127 
128 int main()
129 {
130     freopen("game.in","r",stdin);
131     freopen("game.out","w",stdout);
132     cin>>n;
133     for(int i=0;i<=n;i++)
134         cin>>hand[i].l>>hand[i].r;
135     sort(hand+1,hand+n+1,cmp);
136     res="1";
137     res*=hand[0].l;
138     for(int i=1;i<=n;i++)
139     {
140         bign wei;
141         wei=res/hand[i].r;
142         if(ans<wei)
143             ans=wei;
144         res*=hand[i].l;
145     }//中途过程更新出答案
146     cout<<ans<<endl;
147     return 0;
148 }
View Code

over

原文地址:https://www.cnblogs.com/qswx/p/9308526.html