最大比例


X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。

并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:
16,24,36,54
其等比值为:3/2

现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。

输入格式:
第一行为数字 N (0<N<100),表示接下的一行包含N个正整数
第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。每个整数表示调查到的某人的奖金数额

要求输出:
一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数

测试数据保证了输入格式正确,并且最大比例是存在的。

例如,输入:
3
1250 200 32

程序应该输出:
25/4

再例如,输入:
4
3125 32 32 200

程序应该输出:
5/2

再例如,输入:
3
549755813888 524288 2

程序应该输出:
4/1

资源约定:
峰值内存消耗 < 256M
CPU消耗  < 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。





由题目分析可知,给定的n个数为某一等比数列中的若干项(这些抽出来的若干项可连续、可不连续,且可以相同);其次由等比数列的递推公式an=a1*q^(n-1)可知,这n个数均可以表示为a1*q^k(k为任意非负整数);我们需要求的是可能的最大的公比Q


由等比数列的通式,a1是无关项,则且将n个数前后两两相除并升序排序,得到的n-1项为:q^m   q^n   q^s   q^t   q^u  ...  q^z(这n-1项的每一项直观的理解就是相邻的两个数相差原公比q的多少次方,即中间隔几项),可见,我们只需求出这些项的指数的最大公约数g即可(此时最大公比Q即为q^g);但是这些项可能是分数,给我们带来很大的困难


此路不通,那我们就换种方法求最大公比:让这些q的k次幂项不断地前后两两相除!最终得到的即为最大的公比Q


思路是参考别人的,且看代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<algorithm>
#define MAXN 1000000000000
typedef long long ll;
using namespace std;

ll gcd(ll a, ll b) {// 求最大公约数(参数为整数)
	while (b != 0) {
		ll tmp = a;
		a = b;
		b = tmp % b;
	}
	return a;
}

ll arr[105];// 原数据
struct F {// 定义一个最简分数的结构体
	ll up, dw;// up为分子、dw为分母
	F() {}
	F(ll a, ll b) {
		if (a == 0) {// 注意特殊情况的处理
			up = 0, dw = 1;
			return;
		}
		ll g = gcd(a, b);
		up = a / g, dw = b / g;
	}
	bool operator <(const F &t) const {// 1、比大小  2、sort 
		return (up*t.dw < dw*t.up);
	}
	bool operator ==(const F &t) const {
		return (up*t.dw == dw*t.up);
	}
	F operator /(const F &t) const {
		return F(up*t.dw, dw*t.up);
	}
	void print() {
		printf("%I64d/%I64d\n", up, dw);
	}
}f[105];

int main() {
  	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		//scanf("%I64d", arr[i]);
		cin>>arr[i];
	}

       sort(arr, arr+n);// 排序 
	n = unique(arr, arr+n) - arr - 1;// 去重(得到的n为前后两两相除之后的总个数,所以要在原来的基础上减1,下同)
	for (int i = 0; i < n; i++) {// 前后两两相除
		f[i] = F(arr[i+1], arr[i]);
	}
	
	F ans(MAXN, 1);
	while (n > 1) {// 剩余的个数为1时才结束循环
		sort(f, f+n);// 排序 
		n = unique(f, f+n) - f - 1;// 去重
		if (f[0] < ans) {
			ans = f[0];
		}
		for (int i = 0; i < n; i++) {// 前后两两相除
			f[i] = f[i+1] / f[i];
		}
	}
	if (f[0] < ans) {
		ans = f[0];
	}
	ans.print();
	
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值