UVA1642:Magical GCD

UVA1642:Magical GCD

题意:

给定一个长度为(nleq 10^5),每个数(a_ileq10^{12}),找一个连续子序列使得子序列的公约数与长度的乘积最大。

(T)组数据。

思路:

区间最大公约数模板题。

枚举((i,j))暴力的话时间复杂度为(O(n^2logn)),肯定会超时的。

给定序列(a),连续子段的(gcd)(log(max{a_i}))种可能。

(gcd(1,..,i)=gcd(gcd(1,..,i-1),a(i)))

所以每次固定右端点,向左寻找不同(gcd)的取值。

#include<bits/stdc++.h>
#define PLI pair<long long, int>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll a[maxn];
int n;

ll gcd(ll a, ll b)
{
    if(b == 0) return a;
    return gcd(b, a%b);
}

//fir->gcd sec->右端点索引
vector<PLI> g[maxn];

void solve()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
        g[i].clear();
    }
    for(int i = 1; i <= n; i++)
    {
        ll x = a[i], y = i;
        g[i].push_back({x,y});
        for(int j = 0; j < g[i-1].size(); j++)
        {
            PLI p = g[i-1][j];
            ll t = gcd(x, p.first);
            if(t != x)
            {
                x = t; y = p.second;
                g[i].push_back({x, y});
            }
        }
    }

    ll ans = 0;
    for(int i = 1; i <= n; i++)
    {
        PLI p1, p2;
        for(int j = 0; j < g[i].size()-1; j++)
        {
            p1 = g[i][j];
            p2 = g[i][j+1];
            ans = max(ans, p1.first*(i-p2.second));
        }
        p1 = g[i][g[i].size()-1];
        ans = max(ans, (ll)(i)*p1.first);
    }

    cout << ans << endl;
}

int main()
{
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}
原文地址:https://www.cnblogs.com/zxytxdy/p/12306167.html