P1080 题解
P1080 - Description
有 \(n+1\) 个具备 \(a\) 与 \(b\) 两个数值的人(第 \(0\) 个人不参与计算,但是永远在所有人前面),对所有 \(1\le i\le n\),定义 \(f(i)\):
\[f(i)=\left \lfloor \frac{\prod_{j=0}^{i-1} a_j }{b_i}\right \rfloor
\]
现在让你重新排列队伍,使最大的 \(f(i)\) 最小。(\(1\le i\le n\))
\(1\le n\le 1000,1\le a_i,b_i\le 10^4\)。
P1080 - Solution
像这种存在前后关系,并且操作满足交换律的题目我们应当警惕。这告诉我们这种贪心可以使用临项交换解决。具体地,我们考虑相邻的两项 \(i\) 和 \(i+1\),有:
\[f(i)=\left \lfloor \frac{a_0a_1\cdots a_{i-1}}{b_i}\right \rfloor
\]
\[f(i+1)=\left \lfloor \frac{a_0a_1\cdots a_{i}}{b_{i+1}}\right \rfloor
\]
我们考虑交换 \(i\) 和 \(i+1\) 对答案的影响。
\[f(i)'=\left \lfloor \frac{a_0a_1\cdots a_{i-1}a_{i+1}}{b_i}\right \rfloor
\]
\[f(i+1)'=\left \lfloor \frac{a_0a_1\cdots a_{i-1}}{b_{i+1}}\right \rfloor
\]
如果 \(\arg \max f(i)\) 不是 \(i\) 或 \(i+1\),临项交换前后是对答案没有影响的;如果是 \(i\) 或 \(i+1\),我们发现交换操作就等同于给 \(f(i)\) 乘上 \(a_{i+1}\),给 \(f(i+1)\) 除以 \(a_i\)。如果 \(i\) 交换前更优,那么:
\[\left \lfloor \frac{a_0a_1\cdots a_{i}}{b_{i+1}}\right \rfloor<\left \lfloor \frac{a_0a_1\cdots a_{i-1}}{b_i}\right \rfloor<\left \lfloor \frac{a_0a_1\cdots a_{i-1}a_{i+1}}{b_i}\right \rfloor
\]
也就是说:
\[\frac{a_i}{b_{i+1}}<\frac{a_{i+1}}{b_i}
\]
化简一下,我们得到了 \(a_ib_i<a_{i+1}b_{i+1}\) 的结论。也就是说,如果 \(a_ib_i<a_{i+1}b_{i+1}\),那么交换后一定是不优的。于是我们按照 \(a_ib_i\) 从小到大排序,扫描一遍得出答案即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
long long n,ans;
struct node{
int a,b;
}e[1005];
inline bool cmp(node x,node y){
return x.a*x.b<y.a*y.b;
}
signed main(){
cin>>n;
for(int i=0;i<=n;i++){
cin>>e[i].a>>e[i].b;
}
sort(e+1,e+1+n,cmp);
int fac=e[0].a;
for(int i=1;i<=n;i++){
ans=max(ans,fac/e[i].b);
fac*=e[i].a;
}
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号