蓝桥杯2016c++A组真题&代码第十题最大比例

蓝桥杯2016c++A组真题&代码第十题最大比例

/*
最大比例

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>, 不能通过工程设置而省略常用头文件。

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

 思路:

看代码注释

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
typedef long long ll;
using namespace std;
int N;
const int MAXN = 110;
ll arr[MAXN];
map<ll,map<ll,ll> > all_ex; // all_ex[x][y] = i ,  对 x开方 y 次 的值 
map<ll,map<ll,ll> > all_log;// all_log[x][y] = j  y 的 j 次 为 x  

//对于 开方 和  取对数,可以通过生成再进行查找,从而加快速度 
void init(){
	for(int i=2;i<1e6;i++){
		ll cur = (ll)i*i;
		ll pow = 2;
		while(cur<1e12){
			all_ex[cur][pow] = i;  // 对 cur 开 pow 次方 的答案 为 i 
			all_log[cur][i] = pow;// 对  i 的 pow 次方是 cur   log i cur = pow  
			pow++;
			cur*=i;
		}
	}
} 
struct ratio{
	ll x,y;
	
	ll gcd(ll a,ll b){
		return b==0?a:gcd(b,a%b);
	}
	//两者除以最小公倍数,则获得对应的互质的比值 
	ratio(ll x,ll y):x(x),y(y){
		ll max_s = gcd(x,y);
		this->x/=max_s;
		this->y/=max_s; 
	}
};
vector<ratio> ra_arr;
//思路:
//1.从小到大排序
//2.对第一对比值和后面的 比值进行比较,如果能够保证前面的比值是后面所有比值的基数
//那么就可以得到答案 


// 对 x 进行 pow 次开方 
ll extract(ll x, ll pow){
	// 开 1次方 就是本身  
	//对 1 进行任何开方 都是1  
	if(x ==1 ||pow == 1 )  return x;
	//对map 进行查找,如果能够找到  对 x 进行pow 次开方 ,则返回结果 
	if(all_ex[x].find(pow)!= all_ex[x].end()){
		return all_ex[x][pow];
	}
	//表示开方失败 
	return -1;
}
// 对 temp_x  取 以 base_x 为 底 的对数 
ll log(ll temp_x,ll base_x){
	if(base_x == temp_x) return 1;
	if(all_log[temp_x].find(base_x) != all_log[temp_x].end()){
		return all_log[temp_x][base_x];
	}
	return -1;
}

int main(){
	
	init();
	scanf("%d",&N);
	for(int i =0;i<N;i++){
		scanf("%lld",&arr[i]);
	}
	
	sort(arr,arr+N);
	for(int i =0;i<N-1;i++){
		//去重 
		if(arr[i]==arr[i+1]) continue;
		ra_arr.push_back(ratio(arr[i+1],arr[i]));
	}
	//特殊情况 
	if(N==2){
		ratio temp = ratio(arr[1],arr[0]);
		printf("%lld/%lld\n",temp.x,temp.y);
		return 0;	
	}
	
	//最小的情况 为 2为基数, 最多开 40次  因为 2^40 超过 1e12 
	for(int i=1;i<=40;i++){
		// 取第一个基数对 
		ll x = ra_arr[0].x;
		ll y = ra_arr[0].y;
		//对 x 开 i 次方  得到基数 
		ll base_x = extract(x,i);
		ll base_y = extract(y,i);
		//无法开方 
		if(base_x == -1  || base_y == -1 ) continue;
		bool all_match = true;
		//用第一对基数对所有的比值对进行比较 
		for(int j=0;j<ra_arr.size();j++){
			ll temp_x = ra_arr[j].x;
			ll temp_y = ra_arr[j].y;
			//取对数,这样才能保证是基数关系 
			ll log_x = log(temp_x,base_x);
			ll log_y = log(temp_y,base_y);
			// temp_y 和 base_y 可能有出现1 的情况,对此开方没有意义 
			if(temp_y ==1 && base_y == 1) log_y = log_x;
			if(log_y == -1||log_x == -1||log_x != log_y ){
				all_match = false;
				break;
			}
		}
		if(all_match){
			printf("%lld/%lld\n",base_x,base_y);
			return 0;
		}
	}
	return 0;
} 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值