您的位置:首页 > 其它

【NOIP 2012】 国王游戏

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

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序, 

使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
Input
第一行包含一个整数 n,表示大臣的人数。 

第二行包含两个整数 a 和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。 接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
Output
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
Sample Input

3
1 1
2 3
7 4
4 6


Sample Output

2


Hint
【输入输出样例说明】 

按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和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]为关键字从小到大排序,相同的顺序无所谓。最后再扫一遍,算出答案即可。

    此题需要注意一点:乘除法都要写高精度,且答案有10000多位。

【代码】

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
int N;
int a[1005],b[1005],ka,kb;
int ans[20000],t[20000],lena,lent,tt[20000],t2[20000],len;
void _qst_ab(int l,int r)
{
int i=l,j=r,ma=a[(i+j)>>1],mb=b[(i+j)>>1];
while(i<=j)
{
while(a[i]*b[i]<ma*mb) i++;
while(a[j]*b[j]>ma*mb) j--;
if(i<=j)
{
swap(a[i],a[j]);
swap(b[i],b[j]);
i++;j--;
}
}
if(l<j) _qst_ab(l,j);
if(i<r) _qst_ab(i,r);
}
void _init()
{
scanf("%d%d%d",&N,&a[0],&b[0]);
for(int i=1;i<=N;i++)
scanf("%d%d",&a[i],&b[i]);
}
void _get_t(int Left,int Right)
{
for(int i=1;i<=lent;i++)
{
tt[i]+=t[i]*Left;
tt[i+1]+=tt[i]/10;
tt[i]%=10;
}
lent++;
while(tt[lent]>=10)
{
tt[lent+1]=tt[lent]/10;
tt[lent]%=10;
lent++;
}
while(lent>1&&tt[lent]==0) lent--;
len=lent;
memcpy(t,tt,sizeof(tt));
memset(tt,0,sizeof(tt));
for(int i=1,j=len;i<=len;i++,j--)
t2[i]=t[j];
int x=0,y=0;
for(int i=1;i<=len;i++)
{
y=x*10+t2[i];
tt[i]=y/Right;
x=y%Right;
}
x=1;
while(x<len&&tt[x]==0) x++;
memset(t2,0,sizeof(t2));
for(int i=1,j=x;j<=len;i++,j++)
t2[i]=tt[j];
memcpy(tt,t2,sizeof(t2));
len=len+1-x;
}
bool _cmp()
{
if(len>lena) return true;
if(len<lena) return false;
for(int i=1;i<=len;i++)
{
if(ans[i]<tt[i]) return true;
if(ans[i]>tt[i]) return false;
}
return false;
}
void _solve()
{
_qst_ab(1,N);
t[1]=1;lent=1;
for(int i=1;i<=N;i++)
{
memset(tt,0,sizeof(tt));
len=0;
_get_t(a[i-1],b[i]);
if(_cmp())
{
memcpy(ans,tt,sizeof(tt));
lena=len;
}
}
for(int i=1;i<=lena;i++)
printf("%d",ans[i]);
printf("\n");
}
int main()
{
_init();
_solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: