学习记录2021.7.19

由于本人太菜,平时在洛谷做题,基本都是橙~黄,今天去挑战了一个绿题,结果还是遭到暴击,没办法毕竟还是弱。以下为记录:
题目链接
原题要用高精度,因为懒 这里就不用了。
此题很容易想到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;
}

这种时间复杂度肯定是过大的,必须想更好的方法。
考虑到有如下序列

左手右手
aibi
ai+1bi+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;
}

这种方法被称为相邻项交换法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值