题目来源:https://www.luogu.org/problem/show?pid=1080
用贪心可以解决。
将所有人按左右手的乘积排序,这样一定可以保证结果最优。
现给出证明:
首先,任意相邻两人的顺序对于排在他们前面和后面的人没有影响。(显然)
两人左右手上的数字分别为l[1],r[1],l[2],r[2],令l[1]*r[1]<l[2]*r[2],排在他们前面的所有人左手上的乘积为sum。
若1在2前面,那么两人分得的金币分别为sum/r[1],sum*l[1]/r[2]。
若2在1前面,两人分得的金币分别为sum/r[2],sum*l[2]/r[1]。
现比较max(sum/r[1],sum*l[1]/r[2])和max(sum/r[2],sum*l[2]/r[1])的大小:
因为l[1]*r[1]<l[2]*r[2],故max(sum/r[2],sum*l[2]/r[1])=sum*l[2]/r[1]。
而sum*l[2]/r[1]>sum/r[1]显然成立且sum*l[2]/r[1]>sum*l[1]/r[2]也成立(因为l[1]*r[1]<l[2]*r[2])。
故max(sum/r[1],sum*l[1]/r[2])<max(sum/r[2],sum*l[2]/r[1])。
故1在2前面两人分得的金币的最大值最小。
以此类推,左右手乘积较大的放在后面结果会更优。证毕。
由于此题数据较大,需要用到高精度乘法和除法。
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <cstdio>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
struct node{long long l,r;}c[100010];
long long a[100010],b[100010];
int n;
bool cmp(node a,node b){return a.r*a.l<b.r*b.l;}
bool comp(string s1,string s2)
{
if(s1.size()!=s2.size())return s1.size()>s2.size();
else
{
for(int i=0;i<s1.size();i++)
{
if(s1[i]!=s2[i])return s1[i]>s2[i];
}
}
return 0;
}
string milt(string s,long long t)
{
long long ans[10001]={0};
long long u[10001]={0};
for(int i=0;i<s.size();i++)u[s.size()-i]=s[i]-'0';
for(int i=1;i<s.size()+16;i++)
{
ans[i]+=u[i]*t;
if(ans[i]>=10)ans[i+1]=ans[i]/10;
ans[i]%=10;
}
string e;
int v=s.size()+16;
while(v>1&&ans[v]==0)v--;
for(int i=v;i>=1;i--)e+=(ans[i]+'0');
return e;
}
string chu(string s,long long t)
{
string e;
long long g=0,p=0;
while(g<t&&p<s.size())
{
g=g*10+s[p]-'0';
p++;
}
e+=(g/t+'0');g%=t;
for(int i=p;i<s.size();i++)
{
g=g*10+s[i]-'0';
e+=(g/t+'0');g%=t;
}
if(e.size()==0)e='0';
return e;
}
int main()
{
cin>>n;
for(int i=0;i<=n;i++)
{
cin>>a[i]>>b[i];
c[i].l=a[i];
c[i].r=b[i];
}
sort(c+1,c+n+1,cmp);
string sum="1";
string tot="0";
for(int i=0;i<=n;i++)
{
string u=chu(sum,c[i].r);
if(comp(u,tot))tot=u;
sum=milt(sum,c[i].l);
}
cout<<tot;
return 0;
}