题目描述
X星球的某个大奖赛设了 M 级奖励。
每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。
比如:16,24,36,54,其等比值为:3/2。
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
typedef long long LL;
LL x[N],a[N],b[N];
int cnt=0;
//假设原数列为 a,a*(p/q)^1,a*(p/q)^2,...,a*(p/q)^(n-1)
//假设抽取的数列 b0,b1,...,b(N-1) (从小到大排好序了)
// b1/b0,b2/b0,...,b(N-1)/b0--> (p/q)^x1,(p/q)^x2,...,(p/q)^x(N-1)
// 我们要求的是: (p/q)^k (p/q)>1,所以使k最大,即求 x1~x(N-1)的最大公约数
//这里我们使用更相减损术,因为我们没有得到确切的x1~x(N-1)是多少,我们只有(p/q)^x1,(p/q)^x2,...,(p/q)^x(N-1)这些的值
/*更相减损术:第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2的积与第二步中等数的乘积就是所求的最大公约数。*/
//更相减损术总用较大的减去较小的
/*例子:
98-63=35
63-35=28
35-28=7
28-7=21
21-7=14
14-7=7
所以,98和63的最大公约数等于7。*/
//我们这里要用更相减损术的是指数,所以要让(p/q)^x1,(p/q)^x2,...,(p/q)^x(N-1),两两计算,互除,除到结果为1,即x1=x2,此时幂次为0,结果为1,这其实就是y总的思路,再次感叹y总的才华
//把分子分母分别去算,结果是相同的因为,分子分母的幂次是相同的
LL gcd(LL a,LL b)
{
return b? gcd(b,a%b):a;
}
LL gcd_sub(LL a,LL b)
{
if(a<b) swap(a,b); //更相减损术总是大减小(它们的底数是一样的)
if(b==1) return a;
return gcd_sub(b,a/b);
}
int main()
{
int n;
cin>>n;
for(int i=0; i<n; i++) scanf("%lld",&x[i]);
sort(x,x+n);
for(int i=1; i<n; i++)
{
if(x[i] != x[i-1])
{
LL d=gcd(x[i],x[0]);
a[cnt]=x[i] / d; //得到x[i]/x[0]的分子
b[cnt]=x[0] / d; //得到x[i]/x[0]的分母
cnt++;
}
}
LL up=a[0],down=b[0];
for(int i=1; i<cnt; i++)
{
up=gcd_sub(up,a[i]); //两两求最大公约数
down=gcd_sub(down,b[i]);
}
cout<<up<<"/"<<down<<endl;
return 0;
}
没搞懂为啥得到x[ i ] / x[ 0 ] 分子分母要除以d才能得到
约分啊
明白了 主要是前些天太久没摸了
我也是想半天
写了一篇题解,给了详细严谨的数学推导,感兴趣的可以看看。算法和 y 总的思路是一样的,所有没有代码的注释哦。
https://www.acwing.com/solution/content/238820/
//把分子分母分别去算,结果是相同的因为,分子分母的幂次是相同的
这里不理解
既然都是求最大公约数为什么不能都用gcd就行?最后要用辗转相减法求最大公约数呢?
这里是改版的辗转相减法,减的是指数
懂了,谢谢大佬ORZ
我想问一下,我可以理解为辗转相减法是利用两个指数函数p1^a1 p2^a2 中指数的性质(即:(a,b)=(b,b-a))即求两个指数函数的最大公因数来求两个指数函数p1^a1,p2^a2的最大公因数,但是归根到底不还是求p1^a1 p2^a2的最大公因数吗?理论上可以用gcd来求呀,测试结果是通过样例10/16,说明算法大致也是正确的?
这样本质上是在求所有比例里间距最小是多少,不过求出来也是公因数是p的n次方,所以有些样例可以通过。
👍👍
我们要求的x1~x(N - 1)的最大公约数,与p1^a1 , p2^a1 , … , pn^an的最大公约数不同。举例来说:
原序列:2^2 , 2^6 , 2^12 , 每项除以第一项后得到:2^4,2^6,按照求 p1^a1 , p2^a1 , … , pn^an 的最大公约数,得到的最大公约数应为是2^4,但是如果让原序列的公比等于2^4,可以带回原序列看下 ,2^12 / (2^6) = 2^6 这个结果应该是公比的k次幂(k >= 1),但是2^6并非2^4的正整数次幂
ORZ👍👍👍
终于看懂了!!!
代码写的不是辗转相除吗?
为什么得到的up/down一定是最简形式啊
我们在构建的时候将 (p/q)^x 化简过了
a[cnt]=x[i] / d; //得到x[i]/x[0]的分子
b[cnt]=x[0] / d; //得到x[i]/x[0]的分母
请问一下,这里只约分了一次,不一定会得到最简形式吧
约的是最大的公因数,所以一点是最简的
请问LL d=gcd(x[i],x[0]);
a[cnt]=x[i] / d; //得到x[i]/x[0]的分子
b[cnt]=x[0] / d; //得到x[i]/x[0]的分母
这里为什么要约分呀?
最后结果就是最简的
太强了
为什么是每一项都是k的次幂啊
不是每项都是k次幂,是x1~xn的最大公约数是 k