链接
思路
首先我们先思考一下当只有两个大臣的时候怎么做(当题目没有思路的时候,先考虑数据范围小的情况往往是有帮助的)。 如果国王左手上的数是 $a_0$,两个大臣左右手上的数是$a_1,b_1,a_2,b_2$;那么有两种排法: 第一个大臣排在前面,那么第一个大臣获得 $a_0 / b_1$ 奖赏,第二个获得 $a_0a_1 / b_2$ 奖赏,奖赏最多的大臣获得的奖赏就是 $max(a_0 / b_1, a_0a_1 / b_2)$。 同样,如果第二个大臣排在前面,答案就是$max(a_0 / b_1, a_0a_1 / b_2)$
比较 $ans_1=max(a_0 / b_1, a_0a_1 / b_2)$ 和 $ans_2=max(a_0 / b_1, a_0a_1 / b_2)$,可以写成 $ans_1=a_0 max(b_2,a_1\cdot b_1) / b_1\cdot b_2 ans_2=a_0 max(b_1,a_2\cdot b_2) / b_1\cdot b_2$ 可以想象,如果 $a_1\cdot b_1 ≤ a_2\cdot b_2,$那么 $ans_1 $肯定更小,因为这种情况下 $a_1\cdot b_1 ≤ a_2\cdot b_2 $而 $b_2 ≤ a_2\cdot b_2$,所以 $max(b_2,a_1\cdot b_1) ≤ a_2\cdot b_2 ≤ max(b_1,a_2\cdot b_2)$ 同理,如果$ a_1\cdot b_1 > a_2\cdot b_2$那么$ ans_2 $更小。 于是我们得到一个结论:只有两个人时,把$ a_i \cdot b_i $更小那个放到前面一定更优。
当有更多大臣的时候呢? 考虑最优解满足什么性质。如果我们交换最优解中两个相邻的大臣,那么他们前面的大臣得到的奖赏显然不受影响;而他们后面的大臣也不受影响。(想一想,为什么) 那么把这两个大臣单独拎出来,根据之前的结论,最优解中一定是 ab 较小的放到前面。 这样的话,我们得出结论:最优解中相邻两个大臣,前面的 ab 一定更小。否则可以交换相邻的大臣使得答案更小。
于是最优解肯定是按大臣的 $a\cdot b $排序后的结果。所以将大臣按$ a\cdot b $排好序,计算每个大臣的奖赏就可以了(这题代码难点在于高精度) 通过这道题我们看出一种贪心的分析方式,它尤其适用于“将若干个物品重新排列使得___最小/最大”的问题: 假设我们有一组解,考虑如何调整能使它更优(对于重新排列,一般是交换相邻物品); 最优解一定不能调整。
以来来自《noip杂题选讲 by rqy》
代码
主要是高精度(逃)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
using namespace std;
struct num {
int len,s[10005];//len为数字位数,s数组为每一位上的数字
num(int a=0) { //构造函数
len=0;
memset(s,0,sizeof(s));
while(a) {
len++;
s[len]=a%10;
a/=10;
}
}
num operator * (const num &a) const {
num c;
int x;
for(int i=1; i<=a.len; ++i) {
x=0;
for(int j=1; j<=len; ++j) {
c.s[i+j-1]+=a.s[i]*s[j]+x;
x=c.s[i+j-1]/10;
c.s[i+j-1]%=10;
}
c.s[i+len]=x;
}
c.len=a.len+len;
while(!c.s[c.len] && c.len!=1) c.len--;
return c;
}
num operator / (const int &a) const { //重载整除运算(高精)
num c;
int x=0;
c.len=len;
for(int i=c.len; i>=1; --i) {
x=x*10+s[i];
c.s[i]=x/a;
x%=a;
}
while(!c.s[c.len] && c.len!=1) c.len--;
return c;
}
bool operator < (const num & x) const {//重载'<'(高精比较大小),max函数中要用
if(len!=x.len) return len<x.len;
for(int i=len; i>0; i--)
if(s[i]!=x.s[i])
return s[i]<x.s[i];
return 0;
}
};
struct node { //表示大臣的结构体
int a,b,c;
} p[10005];
int cmp(node a,node b)
{
return a.c<b.c;
}
int n;
int main() {
cin>>n;
for(int i=0; i<=n; ++i) {
cin>>p[i].a>>p[i].b;
p[i].c=p[i].a*p[i].b;
}
num sum(p[0].a),ans;
sort(p+1,p+n+1,cmp);
for(int i=1; i<=n; ++i) {
ans=max(ans,sum/p[i].b);
sum=sum*p[i].a;
}
for(int i=ans.len; i>=1; i--)
cout<<ans.s[i];
return 0;
}