UVA-1642-MagicalGCD[区间最大公约数]

题意:给定长度为n的数列,求这个数列的所有子区间中子区间长度与子区间最大公约数乘积的最大值。

思路:存在一个求区间最大公约数的模板,其思想是固定区间的右端点,依次向左寻找与右端点产生不同最大公约数的点。可在nlogA时间复杂度内完成求所有子区间的不同的最大公约数。A是数列中的最大值。

for (int i = 1; i <= n; i++) {
     ll x = val[i];
     ll y = i;
     g[i].push_back(make_pair(x, y));
     for (int j = 0; j < g[i - 1].size(); j++) {
     pair<ll, ll> p = g[i - 1][j];
     ll gcd = calGcd(x, p.first);
     if (gcd != x) {
     x = gcd;
     y = p.second;
     g[i].push_back(make_pair(x, y));
       }
     }
}
p.first存储的是最大公约数,p.second存储的是左端点的索引。


AC代码:

#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 100005;
typedef long long ll;
vector<pair<ll, ll> > g[MAXN];
ll val[MAXN];
ll calGcd(ll a, ll b) {
    if (b == 0) {
        return a;
    }
    return calGcd(b, a % b);
}
int main() {
    int T;
    cin >> T;
    while (T-- != 0) {
        int n;
        cin >> n;
        g[0].clear();
        for (int i = 1; i <= n; i++) {
            cin >> val[i];
            g[i].clear();
        }

        for (int i = 1; i <= n; i++) {
            ll x = val[i];
            ll y = i;
            g[i].push_back(make_pair(x, y));
            for (int j = 0; j < g[i - 1].size(); j++) {
                pair<ll, ll> p = g[i - 1][j];
                ll gcd = calGcd(x, p.first);
                if (gcd != x) {
                    x = gcd;
                    y = p.second;
                    g[i].push_back(make_pair(x, y));
                }
            }
        }

        ll res = 0;
        for (int i = 1; i <= n; i++) {
            pair<ll, ll> p1, p2;
            for (int j = 0; j < g[i].size() - 1; j++) {
                p1 = g[i][j];
                p2 = g[i][j + 1];
                res = max(res, p1.first * (i - p2.second));
            }
            p1 = g[i][g[i].size() - 1];
            res = max(res, (ll)(i) * p1.first);
        }
        cout << res << endl;
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值