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;
}
posted @ 2025-10-08 16:00  Creativexz  阅读(24)  评论(0)    收藏  举报