题目:
题意:
一共有n位大臣,每个大臣左右手上分别有a、b两个数字,每位大臣可以获得的奖赏为前面所有人左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果,可以重新安排队伍的顺序,求获得奖赏最多的大臣,所获奖赏最少为多少。
分析:
假设前面所有人的左手的数字乘积为,大臣甲左手数字为
,右手数字为
,大臣乙左手数字为
,右手数字为
,甲排在前,奖赏最大为
,乙排在前,奖赏最大为
,令甲在前优于乙在前,则
。
因为,所以
。可得
,因此可推得
,
即,所以只需要数组按照
从小到大排序即可得到最佳的顺序,再按顺序求出获得奖赏最多的大臣所获奖赏即可。由于数据范围比较大,因此还需要进行高精度运算。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,sum[11000],len=1,ans[11000],tot=0,sh[11000],l;
struct node{
int x,y;
long long z;
}a[11000];
bool cmp(node a,node b)
{
return a.z<b.z;
}
bool cp(int l)
{
if(len-l>tot)return true;
if(len-l<tot)return false;
for(int i=1;i<=tot;i++)
{
if(ans[i]<sh[i])return true;
if(ans[i]>sh[i])return false;
}
return false;
}
void c(int x)
{
for(int i=1;i<=len;i++)
sum[i]*=x;
for(int i=1;i<=len;i++)
{
if(sum[i]>9)
{
sum[i+1]+=sum[i]/10;
sum[i]%=10;
if(i==len)len++;
}
}
return;
}
void chu(int x)
{
bool ok=false;
memset(sh,0,sizeof(sh));
for(int i=1;i<=len;i++)
sh[i]=sum[len-i+1];
int yu=0,l=0;
for(int i=1;i<=len;i++)
{
int tmp=(sh[i]+yu*10)/x;
yu=(sh[i]+yu*10)%x;
sh[i]=tmp;
if(ok||tmp)
ok=true;
else l++;
}
for(int i=l+1;i<=len;i++)
sh[i-l]=sh[i];
if(l==len)l=len-1;
if(cp(l))
{
for(int i=1;i<=len-l;i++)
ans[i]=sh[i];
tot=len-l;
}
return;
}
int main()
{
sum[1]=1;
scanf("%d",&n);
for(int i=0;i<=n;i++)scanf("%d %d",&a[i].x,&a[i].y);
for(int i=1;i<=n;i++)a[i].z=a[i].x*a[i].y;
sort(a+1,a+n+1,cmp);
for(int i=0;i<=n;i++)
{
c(a[i].x);
if(i==n-1)chu(a[n].y);
}
if(ans[1]==0&&(tot==1))printf("1");
else
{
for(int i=1;i<=tot;i++)printf("%d",ans[i]);
}
return 0;
}