Noip2012 Day1 T2 国王游戏(贪心+高精度)

来源:互联网 发布:程序员人资面试题 编辑:程序博客网 时间:2024/05/29 13:40

问题描述

恰逢 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。

思路

一道贪心的题目
20%可以深搜全排列
60%可以贪心
100%需要高精度

贪心的思想:假设两个人的位置互换,不会影响前面也不会影响后面
设这两个人分别为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]
所以就从a[i]*b[i]由小到大排序
注意数据范围很大,要拿满分一定要高精度

代码

#include <iostream>#include <string>#include <algorithm>using namespace std;int n,ch[10001],ch1[10001],c[10001];struct w{int x,y;}a[1001]; //结构体int ans[10001];int print(int aa[]){    for(int i=1;i<=aa[0];i++)    cout<<aa[i];    cout<<endl;}//输出答案bool cmp(w a1,w a2){    return a1.x*a1.y<a2.x*a2.y;}//sort的条件bool bj(int aa[],int bb[]){    if(aa[0]>bb[0])return true;    if(aa[0]<bb[0])return false; //位数判断    for(int i=1;i<=aa[0];i++)    {        if(aa[i]>bb[i])return true;        if(aa[i]<bb[i])return false;    }//一位一位比较 }//这是比较两个数的大小,如果第一个数大就return true,不然就return falsevoid div(int aa[],int bb){    for(int i=0;i<=10000;i++)ch1[i]=0;    for(int i=0;i<=10000;i++)ch[i]=0;    int x=0,s=1;    for(int i=1;i<=aa[0];i++)    {        ch1[i]=(x*10+aa[i])/bb;        x=(x*10+aa[i])%bb;    }    while(ch1[s]==0)s++;    for(int i=s,j=1;i<=10000;i++,j++)    ch[j]=ch1[i];    ch[0]=aa[0]-s+1;    if(ch[0]==0)ch[0]=1;}//高精除以低精,不用多说void copy(int aa[],int bb[]){    for(int i=0;i<=10000;i++)    aa[i]=bb[i];}//把数组aa改成数组bbvoid cheng(int aa[],int bb){    int cc[10001],x=0;    for(int i=0;i<=10000;i++)cc[i]=0;    cc[0]=aa[0];    for(int i=10000,j=aa[0];i>=1,j>=1;i--,j--)    cc[i]=aa[j];    c[0]=0;    for(int i=10000;i>=1;i--)    {        cc[i]*=bb;        cc[i]+=x;            x=cc[i]/10;        cc[i]%=10;    }    int s=1;    while(cc[s]==0)s++;    c[0]=10000-s+1;    for(int i=1;i<=c[0];i++)    c[i]=cc[10000-c[0]+i];}//其实刚开始我还想高精×高精,感觉会超时,后面发现其实高精×低精就行了,因为b<=10000int main(){    cin>>n;    for(int i=0;i<=n;i++)    cin>>a[i].x>>a[i].y; //输入    sort(a+1,a+n+1,cmp); //对ai*bi进行升序排序,注意国王永远是在第一个    c[1]=1;c[0]=1; //赋初值    for(int i=0;i<=n;i++)    {        if(i>0)div(c,a[i].y); //如果不是国王的话,就用那个公式,用前面所有人左手的乘积除以自己右手的        else ch[0]=1; //如果是国王就肯定是0,因为前面没有人,0除以任何0除外的数都为0,但是位数记得要改为1        cheng(c,a[i].x); //当前所有人左手的乘积,给下一个人用        if(bj(ans,ch)==false)copy(ans,ch); //如果当前答案比最终答案大,那么最终答案改为当前答案    }    print(ans); //输出结果    return 0;}
原创粉丝点击