BZOJ 4052 Magical GCD

Description

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

Input

第一行一个整数\(T\),表示数据组数。
对于每组数据第一行一个整数\(N\),表示序列长度。接下来一行有\(N\)个整数,表示序列中的每个元素。

Output

对于每组数据,输出序列中所有连续子段中最大的GCD乘长度。

Sample Input

1
5
30 60 20 20 20

Sample Output

80

HINT

\(N \le 100000\)

由于gcd每次变化至少减少一半,序列中本质不同的gcd子段只有\(O(nlogn)\)个。对于每个位置\(i\),我们枚举一个gcd值d,二分出一个最小的\(j\)使得\(gcd_{seq_{j \sim i}} = d\)。这个可以用ST表实现,复杂度\(O(nlog^{2}n) \times O(gcd)\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

typedef long long ll;
#define maxn (100010)
ll rmq[20][maxn]; int N,bit[maxn*2];

inline ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; }

inline ll query(int l,int r)
{
    int len = r-l+1;
    return gcd(rmq[bit[len]][l],rmq[bit[len]][r-(1<<bit[len])+1]);
}

inline ll work()
{
    ll ret = 0;
    for (int i = 1;i <= N;++i)
    {
        ll now = rmq[0][i];
        for (int last = i,l,r,mid;last;)
        {
            l = 1,r = last;
            while (l <= r)
            {
                mid = (l + r) >> 1;
                if (query(mid,i) != now) l = mid + 1;
                else r = mid - 1;
            }
            ret = max(ret,(i-r)*now);
            if (r) now = gcd(now,rmq[0][r]); last = r;
        }
    }
    return ret;
}

int main()
{
    freopen("4052.in","r",stdin);
    freopen("4052.out","w",stdout);
    for (int i = 1;(1<<i)<=200000;++i) for (int j = 1<<(i-1);j < (1<<i);++j) bit[j] = i-1;
    int T; scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&N);
        for (int i = 1;i <= N;++i) scanf("%lld",rmq[0]+i);
        for (int i = 1;(1 << i) <= N;++i)
            for (int j = 1;j+(1<<i)-1 <= N;++j) rmq[i][j] = gcd(rmq[i-1][j],rmq[i-1][j+(1<<(i-1))]);
        printf("%lld\n",work());
    }
    fclose(stdin); fclose(stdout);
    return 0;
}

转载于:https://www.cnblogs.com/mmlz/p/4497082.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值