[Cerc2013]Magical GCD

https://vjudge.net/problem/UVA-1642

题意:在一个序列中,找出一段连续的序列,使得长度*gcd最大

固定右端点,当左端点从左向右移动时,gcd不变或变大

gcd相同时,序列越长越好

所以相同的gcd只记录最靠左的位置

当右端点由r转移向r+1时

重新计算gcd,然后去重

gcd最多只会有log个

#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 100001
using namespace std;
typedef long long LL;
LL a[N];
void read(LL &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
struct node
{
    int sum,s[45];
    LL gcd[45];
}cur,nxt;
LL getgcd(LL a,LL b) { return !b ? a : getgcd(b,a%b); }
int main()
{
    int T,n;
    LL ans,g;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) 
        read(a[i]);
        cur.gcd[1]=a[1]; cur.sum=cur.s[1]=1;
        ans=a[1];
        for(int r=2;r<=n;r++)
        {
            nxt.sum=1;
            nxt.s[1]=cur.s[1];
            nxt.gcd[1]=getgcd(cur.gcd[1],a[r]);
            for(int l=2;l<=cur.sum;l++)
            {
                g=getgcd(cur.gcd[l],a[r]);
                if(g!=nxt.gcd[nxt.sum]) 
                {
                    ans=max(ans,nxt.gcd[nxt.sum]*(r-nxt.s[nxt.sum]+1));
                    nxt.sum++;
                    nxt.gcd[nxt.sum]=g;
                    nxt.s[nxt.sum]=cur.s[l];
                }    
            }
            ans=max(ans,nxt.gcd[nxt.sum]*(r-nxt.s[nxt.sum]+1));
            if(a[r]!=nxt.gcd[nxt.sum]) 
            {
                nxt.gcd[++nxt.sum]=a[r],nxt.s[nxt.sum]=r;
                ans=max(ans,a[r]);
            }
            cur=nxt;
        }
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7401367.html