下面给出贪心做法的证明:
left right
k x y
p1 x1 y1 或 针对这种情况 我们得到ans1=max(x/y1, x*x1/y2)
p2 x2 y2
left right
k x y
p2 x2 y2 针对这种情况 我们得到ans2=max(x/y2, x*x2/y1)
p1 x1 y1
设k1=x/y1, k2=x*x1/y2, k3=x/y2,k4=x*x2/y1
由于x1是整数,我们可以得到k1<k4,k2<k3
若ans1<ans2 我们不难得出k2<k4
展开得到 x1*y1<x2*y2
同理,我们可以以上述不等式为条件,倒着推出ans1<ans2 所以为了让结果更小,我们需要将大臣左右手数字成绩从小到大排序,然后求出其前面所有人左手乘积除以自己右手的最大值。
这道题必须用高精,否则会炸掉。
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int n;
struct hand
{
int l;
int r;
}a[1010];
bool cmp(const hand &a,const hand &b)
{
return a.l*a.r<b.l*b.r;
}
int ans[40000+10],lans;
int tmp[40000+10],ltmp;
int mmax[40000+10],lmmax;
int ans0[40000+10],lans0;
void f1(int i) // tmp=ans/a[i].y
{
memset(tmp,0,sizeof(tmp));
ltmp=lans;
lans0=lans;
int y=a[i].r;
for(int j=1;j<=lans;j++)
{
ans0[j]=ans[j];
}
for(int j=lans;j>=1;j--)
{
ans0[j-1]+=ans0[j]%y*10;
tmp[j]=ans0[j]/y;
}
while(tmp[ltmp]==0&<mp!=0) ltmp--;
}
void f2() // max(tmp,mmax)
{
if(ltmp<lmmax) return;
if(ltmp==lmmax)
{
for(int i=ltmp;i>=1;i--)
{
if(tmp[i]<mmax[i]) return ;
else if(tmp[i]>mmax[i]) break;
}
}
lmmax=ltmp;
for(int i=1;i<=ltmp;i++)
mmax[i]=tmp[i];
}
void f3(int i) // ans*=a[i].l
{
int y=a[i].l;
for(int j=1;j<=lans;j++)
ans[j]*=y;
for(int j=1;j<=lans;j++)
{
ans[j+1]+=ans[j]/10;
ans[j]%=10;
}
while(ans[lans+1]!=0)
{
lans++;
ans[lans+1]=ans[lans]/10;
ans[lans]%=10;
}
}
void output()
{
for(int i=lmmax;i>=1;i--)
{
cout<<mmax[i];
}
cout<<endl;
}
int main()
{
// freopen("game.in","r",stdin);
// freopen("game.out","w",stdout);
scanf("%d",&n);
n++;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
}
sort(a+2,a+n+1,cmp);
while(a[1].l) ans[++lans]=a[1].l%10,a[1].l/=10;
for(int i=2;i<=n;i++)
{
f1(i);
f3(i);
f2();
}
output();
// fclose(stdin);
// fclose(stdout);
return 0;
}