【NOIP2012】国王游戏
本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P1080
这道题用到了贪心的思想,与简单的贪心不同,最优解并不能一眼就看出来,需要通过列式比较。我们设想对于任意的两位大臣x和y,他们两个的排列顺序会对答案有影响。假设国王和之前的大臣左手上的数乘积为pre,若x排在y前,ans1=max(pre/x.b,pre*x.a/y.b),ans2=max(pre/y.b,pre*y.a/x.b)。因为必有pre*x.a/y.b>pre/y.b,pre*y.a/x.b>pre/x.b,若要ans1<ans2,则pre*x.a/y.b<pre*y.a/x.b,否则pre*x.a/y.b将会成为最大的数,也就是ans1大于ans2,而我们最终希望答案越小越好,所以就按a*b作为优先级将大臣们排序,最终可以使得获得奖赏最多的大臣所获金币数最小。这是本题的关键,也是一种非常重要的贪心思想,在那道烹调方案中,就要用到。
有了以上分析就可以有60分,但本题ans的最大值可以达到10^5000左右!!!要用高精度,这才是最坑的。弄了好久才过去,借着这个契机,好好改改我的高精度模板。。。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<string> 5 using namespace std; 6 const int maxn=1005,maxl=5005; 7 int n,ka,kb; 8 struct BigInteger { 9 int num[maxl],len; 10 BigInteger(int x=0) { 11 memset(num,0,sizeof(num)); 12 num[1]=x;len=1; 13 } 14 bool operator < (const BigInteger& rhs) const { 15 if(len==rhs.len) { //小于运算符可将其他比较运算符表示出来 16 for(int i=len;i>=1;--i) 17 if(num[i]!=rhs.num[i]) return num[i]<rhs.num[i]; 18 return false; 19 } 20 else return len<rhs.len; 21 } 22 void operator * (const int& rhs) { //高精乘低精 23 for(int i=1;i<=len;++i) num[i]*=rhs; //先每位乘上再处理进位 24 for(int i=1;i<=len;++i) 25 for(int j=i;num[j]>9;++j) { 26 num[j+1]+=num[j]/10; 27 num[j]%=10; 28 } 29 len+=15; 30 while(!num[len]&&len>1) --len; 31 } 32 BigInteger operator / (const int& rhs) const { 33 BigInteger ans=*this; 34 for(int i=ans.len;i>=1;--i) { 35 ans.num[i-1]+=ans.num[i]%rhs*10; 36 ans.num[i]/=rhs; 37 } 38 while(!ans.num[ans.len]&&ans.len>1) --ans.len; 39 return ans; 40 } 41 void print() { 42 for(int i=len;i>=1;--i) printf("%d",num[i]); 43 } 44 } now,ans; 45 struct minister { 46 int a,b; 47 bool operator < (const minister& rhs) const { 48 return a*b<rhs.a*rhs.b; 49 } 50 } M[maxn]; 51 int main() { 52 scanf("%d%d%d",&n,&ka,&kb); 53 for(int i=1;i<=n;++i) scanf("%d%d",&M[i].a,&M[i].b); 54 sort(M+1,M+n+1); 55 now=BigInteger(1);now*ka; 56 for(int i=1;i<=n;++i) { 57 if(ans<now/M[i].b) ans=now/M[i].b; 58 now*M[i].a; 59 } 60 ans.print(); 61 return 0; 62 }