CF1349A
WeLikeStudying · · 题解
顶楼大佬的思路真是妙,我就只说一些理解和补充吧。
如果理解大佬的思路的话,你就会明白:
- 这道题不需要
O(n) 的后缀\gcd 。 - 这道题甚至不需要开数组。(当然只是为了省空间)
- 更新:提供更紧的时间界
O(n+\log(\max\lbrace a_i \rbrace)) 而非O(n\log(\max\lbrace a_i \rbrace)) 。
题意是要求:
那么拆开来看,对于每一个质数
容易看出这是求
一种思路是直接暴力分解因式,这样是
但大佬将这个式子做了一个变形:
一开始,我大惑不解:
但后来,我明白了:对于每个质数
而这两个式子可比
我们继续推式子:
(似乎题解区的大佬考虑了重复的情况呢,虽然这里并不会影响正确性,在这里本蒟蒻提出一个小小的批评)
依照上面的方法,每到一个
//尊前不用翠眉颦,人生如逆旅,我亦是行人
#include<fstream>
using namespace std;
const int MAXN=1e5+1;
int n,a[MAXN],g;
long long dc=1;
long long gcd(long long a,long long b)
{
return (a%b==0)?b:gcd(b,a%b);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
g=a[0];
dc=1ll*a[0]*a[1];
for(int i=1;i<n-1;i++)
{
long long part=1ll*g*a[i];
g=gcd(a[i],g);
dc=gcd(dc,part);
}
dc=gcd(dc,1ll*g*a[n-1]);
g=gcd(a[n-1],g);
printf("%lld",dc/g);
return 0;
}
同样给出不需要数组的程序。时间复杂度
//尊前不用翠眉颦,人生如逆旅,我亦是行人
#include<fstream>
using namespace std;
int n,a,g;
long long dc;
long long gcd(long long a,long long b)
{
return !b?a:gcd(b,a%b);
}
int main()
{
scanf("%d",&n);
g=dc=0;
for(int i=0;i<n;++i)
{
scanf("%d",&a);
dc=gcd(1ll*g*a,dc);
g=gcd(a,g);
}
printf("%lld",dc/g);
return 0;
}
感谢各位大佬提供的思路。
最后给出一个有趣又简单的说明
- 构造出一组数据,使得
\gcd 运算n 次才能结束,且数据参数尽可能小。 - 我们尝试贪心选取。
- 第一个数显然是
1 。 - 第二个数至少是
2 ,取2 ,这时需要运算1 次。 - 第三个数显然是
a+2b 型,取3 ,这时需要运算2 次。 - 于是我们构造出了这样一个数列:
1,2,3,5,8,13,21,34,55,89,144,233,377\dots - 这个数列显然是斐波那契数列的一部分,其通项公式应该是:
\frac1{\sqrt 5}\bigg[\bigg(\frac{1+\sqrt5}2\bigg)^{n+2}-\bigg(\frac{1-\sqrt5}2\bigg)^{n+2}\bigg] -
-
- 设
\gcd 较大的参数为a ,有:\frac1{\sqrt 5}\bigg(\frac{1+\sqrt5}2\bigg)^{n+2}=a n+2=\log_{\frac {1+\sqrt5}2}{\sqrt 5 a} - 考虑第一次的无效操作,时间复杂度上界应该是:
O(-1+\log_{\frac {1+\sqrt5}2}{\sqrt 5 a}) - 也就是:
O(\log a)