bzoj 4052: [Cerc2013]Magical GCD
4052: [Cerc2013]Magical GCD
Description
给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12。
求一个连续子序列,使得在所有的连续子序列中,它们的GCD值乘以它们的长度最大。
Sample Input
1
5
30 60 20 20 20
5
30 60 20 20 20
Sample Output
80
题解:
有点神。。
看了题解说以一个点开头的序列的gcd种数最多logN种(完全不知道为什么。。。)
我们可以用st表维护一个区间的gcd值,查找最长gcd相同的区间可以用二分。
#include<stdio.h> #include<iostream> #include<math.h> using namespace std; const int N=100005; #define ll long long int T,n,i,j,x,l,r,mid,Log[N]; ll ans,f[N<<1][20]; inline void read(ll &v){ char ch,fu=0; for(ch='*'; (ch<'0'||ch>'9')&&ch!='-'; ch=getchar()); if(ch=='-') fu=1, ch=getchar(); for(v=0; ch>='0'&&ch<='9'; ch=getchar()) v=v*10+ch-'0'; if(fu) v=-v; } ll gcd(ll a,ll b) { if(b==0) return a;else return gcd(b,a%b); } ll solve(int l,int r) { int x=Log[r-l+1]; return gcd(f[l][x],f[r-(1<<x)+1][x]); } int main() { scanf("%d",&T); for(i=1;i<=100000;i++) Log[i]=log2(i); while(T--) { scanf("%d",&n); ans=0; for(i=1;i<=n;i++) read(f[i][0]); for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) f[i][j]=gcd(f[i][j-1],f[i+(1<<j-1)][j-1]); for(i=1;i<=n;i++) { x=i; while(x<=n) { l=x;r=n; ll s=solve(i,x); while(l<=r) { mid=(l+r)>>1; if(s==solve(i,mid)) l=mid+1;else r=mid-1; } ans=max(ans,solve(i,r)*(r-i+1)); x=l; } } printf("%lld\n",ans); } return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。