由于本人太菜,平时在洛谷做题,基本都是橙~黄,今天去挑战了一个绿题,结果还是遭到暴击,没办法毕竟还是弱。以下为记录:
题目链接
原题要用高精度,因为懒 这里就不用了。
此题很容易想到O(n*n!)的做法,即枚举所有全排列并按照题意模拟,代码如下:
#include <cstdio>
#include <algorithm>
#include <climits>
#define INF LLONG_MAX
#define ulong unsigned long long
const int M=1002;
using namespace std;
struct gold {
ulong left,right;
}a[M];
bool cmp1(gold x,gold y) {return x.right<y.right||(x.right==y.right&&x.left>y.left);}
bool cmp2(gold x,gold y) {return !cmp1(x,y);}
ulong solve(int n) {
ulong maxn=0;
ulong ji[M];
fill(ji+1,ji+1+M,1);
ji[0]=a[0].left;
for(int i=1; i<=n; i++) {
ji[i]*=(ji[i-1]*a[i].left);
maxn=max(maxn,ji[i-1]/a[i].right);
}
return maxn;
}
int main(){
int n;
scanf("%d",&n);
for(int i=0; i<=n; i++) {
scanf("%llu%llu",&a[i].left,&a[i].right);
}
sort(a+1,a+n+1,cmp2); //反向排序,确保枚举到所有排列
ulong res=INF;
res=min(res,solve(n));
while(prev_permutation(a+1,a+n+1,cmp1)) {
res=min(res,solve(n));
}
printf("%llu\n",res);
return 0;
}
这种时间复杂度肯定是过大的,必须想更好的方法。
考虑到有如下序列
左手 | 右手 |
---|---|
ai | bi |
ai+1 | bi+1 |
不妨假设最大值在这两人中间产生,则可能的两种最大值分别为
设它们分别为ans1,ans2,假设ans1<ans2,则分下列情况讨论:
1.ans1=1/bi,ans2=1/bi+1,则有bi+1>bi;
2.ans1=ai/bi+1,ans2=1/bi+1,则有ai<1,显然不成立;
3.ans1=ai/bi+1,ans2=ai+1/bi,则有aibi<ai+1bi+1;
还有一种就不写了,与2类似
可以证明,如果采取1的贪心策略,那么得不到正确答案,所以我们按照3,采取如下贪心策略:
按照aibi从小到大排序
代码如下:
#include <cstdio>
#include <algorithm>
#include <climits>
#define INF ULLONG_MAX-1
const int M=1002;
typedef unsigned long long ulong;
using namespace std;
struct gold {
ulong left,right;
}a[M];
bool cmp1(gold x,gold y) {return x.left*x.right<(y.left*y.right);}
ulong conquer(int n) {
ulong maxn=0,ji[M];
fill(ji+1,ji+1+M,1.0);
ji[0]=a[0].left;
for(int i=1; i<=n; i++) {
ji[i]*=(ji[i-1]*a[i].left);
maxn=max(maxn,ji[i-1]/a[i].right);
}
return maxn;
}
int main(){
int n;
scanf("%d",&n);
for(int i=0; i<=n; i++) {
scanf("%llu%llu",&a[i].left,&a[i].right);
}
sort(a+1,a+n+1,cmp1);
ulong res=conquer(n);
printf("%llu",res);
return 0;
}
这种方法被称为相邻项交换法