C. Orac and LCM(数论lcm, gcd)

C. Orac and LCM

思路

题目非常简单,就是求 g c d ( l c m ( i ,   j ) )   f o r   i   i n   r a n g e ( n ) ,   f o r   j   i n   r a n g e ( n ) ,   i   <   j gcd(lcm_(i,\ j))\ for\ i\ in\ range(n),\ for\ j\ in\ range(n),\ i\ <\ j gcd(lcm(i, j)) for i in range(n), for j in range(n), i < j

对于包含 a 1 a_1 a1的项有, g c d   ( l c m 1 , 2 , l c m 1 , 3 , l c m 1 , 4 , … … , l c m 1 , n − 1 , l c m 1 , n ) gcd\ (lcm_{1,2}, lcm_{1, 3}, lcm_{1, 4}, ……, lcm_{1, n - 1}, lcm_{1, n}) gcd (lcm1,2,lcm1,3,lcm1,4,lcm1,n1,lcm1,n)

由于每一项都包含 a 1 a_1 a1,所以整体的 g c d   = l c m ( a 1 , g c d ( a 2 , a 3 , a 4 , … … , a n − 1 , a n ) ) gcd\ = lcm(a_1 , gcd(a_2, a_3, a_4, ……, a_{n - 1}, a_{n})) gcd =lcm(a1,gcd(a2,a3,a4,,an1,an))

同样的其最后的 G C D GCD GCD就是这 n n n项的 g c d gcd gcd的共同的 g c d gcd gcd,通样的对于所有的 g c d ( a i … … a n ) gcd(a_i …… a_n) gcd(aian)我们可以通过对原数组从后开始求 g c d gcd gcd,求得。

正确代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

inline ll read() {
    ll f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    } 
    while(c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return f * x;
}

const int N = 1e5 + 10;

ll a[N], b[N];
int n;

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

ll lcm(ll a, ll b) {
    return a * b / gcd(a, b);
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    n = read();
    for(int i = 1; i <= n; i++)
        a[i] = read();
    for(int i = n; i >= 1; i--) b[i] = gcd(b[i + 1], a[i]);
    ll ans = 0;
    for(int i = 1; i <= n; i++)
        ans = gcd(ans, lcm(a[i], b[i + 1]));
    printf("%lld\n", ans);
    return 0;
}

一个不会优化的代码

大概思路就是只有当一个质因子在最少n - 1个数中出现过,其对整体的 g c d gcd gcd才有贡献,所以我们只需要统计这些质因子出现的次数,一个质因子出现了 n − 1 n - 1 n1次,即是他的最小次方的出现项对整体有贡献,如果一个数出现了 n n n次,即是他的次二小次方项对整体有贡献。

但是这个代码的复杂度过高了,优化不出来 O ( 200000 ∗ ( 200000 以 内 的 质 数 个 数 ) ) O(200000 * (200000以内的质数个数)) O(200000(200000))

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 2e5 + 10;

int prime[N], n, cnt, flag[N];
vector<ll> num[N];
bool st[N];

void init() {
    st[0] = st[1] = true;
    for(int i = 2; i < N; i++) {
        if(!st[i])  prime[cnt++] = i;
        for(int j = 0; j < cnt && prime[j] * i < N; j++) {
            st[i * prime[j]] = true;
            if(i % prime[j] == 0)   break;
        }
    }
}

int main() {
    // freopen("in.txt", "r", stdin);
    scanf("%d", &n);
    init();
    int t;
    for(int i = 0; i < n; i++) {
        scanf("%d", &t);
        for(int j = 0; prime[j] <= t; j++) {
            ll sum = 1;
            while(t % prime[j] == 0) {
                t /= prime[j];
                sum *= prime[j];
            }
            if(sum != 1) {
                flag[j]++;
                num[j].push_back(sum);
            }
        }
    }
    ll ans = 1;
    for(int i = 0; i < cnt; i++) {
        if(flag[i] == n - 1) {
            sort(num[i].begin(), num[i].end());
            ans *= num[i][0];
        }
        if(flag[i] == n) {
            sort(num[i].begin(), num[i].end());
            ans *= num[i][1];
        }
    }
    printf("%lld\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值