[bzoj4488]最大公约数
我们还是考虑分别统计每个位置开始时的答案,然后不难发现 1、gcd值单调不增 2、对于一个gcd值,同一个七点比他小的gcd值最多是其1/2 所以我们的len至少也应该是两倍,然后考虑倍增就行了
- 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
int n;
ll a[N],db[N][20];
inline void init(){
for(int i=1;i<=n;i++)db[i][0]=a[i];
for(int i=1;1<<i <=n;i++)
for(int j=1;j+(1<<i)-1<=n;j++){
db[j][i]=gcd(db[j][i-1],db[j+(1<<(i-1))][i-1]);
}
}
ll findans(int id,int len){
int cur=id;
ll ans=0;
for(int i=0;i<=17;i++)if(1<<i&len){
ans=gcd(db[cur][i],ans);cur=cur+(1<<i);
}
return ans;
}
int findpos(int id,ll G){
int cur=id;
ll nw=0;
for(int i=17;i>=0;i--)if(db[cur][i]){
ll nwg=gcd(db[cur][i],nw);
if(nwg>=G){
nw=nwg;cur=cur+(1<<i);
}
}
return cur-1;
}
ll ans=0;
inline void getans(int pos)
{
int nowlen=1;
while(nowlen<=n-pos+1){
ll GCD=findans(pos,nowlen);
int R=findpos(pos,GCD);
nowlen=R-pos+1;
ans=max(ans,nowlen*GCD);
nowlen*=2;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
init();
for(int i=1;i<=n;i++)
getans(i);
printf("%lld\n",ans);
}