https://www.luogu.org/problemnew/show/P1080

这道题要获奖赏最多的大臣所获奖赏尽量低,但是是不能二分的,因为不能根据一个最多获奖赏数额来确定最优排序。

考虑一个已经排好序的序列,看第i-1和i个大臣,设前i-2个大臣的左手之积是x,第i-1个大臣左ai-1,右bi-1,第i个大臣左ai,右bi。

不管他俩换不换,对于序列这两人之前以及之后没有任何影响。

如果这两人不换位置,这两人最高奖赏是max{①x/b[i-1],②x*a[i-1]/b[i]},如果换,则是max{③x/b[i],④x*a[i]/b[i-1]}

一定有①<④,③<②。

若换前的max大于换后的max,则换了对于最终答案可能好,可能没影响,有变好的趋势,至少不会变差。

若换前的max小于换后的max,则不换。

根据这两个max个进行sort()完成后,对于任意响邻两个人,都不换为好,于是就ok了。

(看题解,只需以a*b为关键字升序排序就可以了,因为不换等价于④>②,换等价于④<②,④==②的话一样)

这题还要高精度,高精和普通的乘除都O(n),乘上n最大取10^4,最后运算应该是要大于10^8的,交上去感觉要超时,结果没有,而且还挺快的,不知道为什么,看来对时间复杂度分析很不过关。

#include<bits/stdc++.h>
using namespace std;

int n;
string ans,sum;
struct Man{
	int a, b;
}man[10005];

bool cmp(Man x,Man y)
{
	return max(1.0/x.b,x.a*1.0/y.b)<max(1.0/y.b,y.a*1.0/x.b);
}

const int L=10005;
int na[L];
string mul(string a,int b)//高精度a乘单精度b
{
    string ans;
    int La=a.size();
    fill(na,na+L,0);
    for(int i=La-1;i>=0;i--) na[La-i-1]=a[i]-'0';
    for(int i=0;i<La;i++) na[i]=na[i]*b;    
    int pos;
    for(pos=0;pos<La-1;pos++)na[pos+1]+=na[pos]/10,na[pos]%=10;
    while(na[pos])na[pos+1]=na[pos]/10,na[pos]%=10,pos++;
    while((!na[--pos])&&pos)continue; 
    pos++;
    for(int i=pos-1;i>=0;i--)ans+=na[i]+'0';
    return ans;
}

string div(string a,int b)//高精度a除以单精度b
{
    string r,ans;
    int d=0;
    if(a=="0") return a;//特判
    for(int i=0;i<a.size();i++)
    {
            r+=(d*10+a[i]-'0')/b+'0';//求出商
            d=(d*10+(a[i]-'0'))%b;//求出余数
    }
  //此时d就是a%b 
    int p=0;
    for(int i=0;i<r.size();i++)
    if(r[i]!='0') {p=i;break;}
    if(p==0&&r[p]=='0')p=r.size()-1;
    return r.substr(p);
}

string maxx(string a,string b)
{
	if(a.length()!=b.length())return a.length()>b.length()?a:b;
	return max(a,b);
}

void calc()
{
	ans="0";
	sum=mul("1",man[0].a);
	for(int i=1;i<=n;i++)
	{
		ans=maxx(ans,div(sum,man[i].b));
		sum=mul(sum,man[i].a);
	}
}

int main()
{
	freopen("input.in","r",stdin);
	cin>>n;
	for(int i=0;i<=n;i++)cin>>man[i].a>>man[i].b;
	sort(man+1,man+1+n,cmp);
	calc();
	cout<<ans<<endl;
	
	return 0;
}