bzoj 4052: [Cerc2013]Magical GCD

4052: [Cerc2013]Magical GCD

Description

给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12。 
求一个连续子序列,使得在所有的连续子序列中,它们的GCD值乘以它们的长度最大。

Sample Input

1
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;
}

  

posted @ 2016-07-19 18:10  lwq12138  阅读(427)  评论(0编辑  收藏  举报