[BZOJ4454][C Language Practice][O(1)GCD]

来源:互联网 发布:java concat函数用法 编辑:程序博客网 时间:2024/04/29 16:40

[BZOJ4454][C Language Practice][GCD]

题目大意:

这里写图片描述

思路:

  • 如果对于每两个数都求一次gcd显然会超时。

  • 考虑O(N)预处理,O(1)求gcd。

  • 不妨设m=n,可以在O(m2)也就是O(N)的时间里求出m范围内的gcd(辗转相除递推)

  • m范围外的数X,一定可以分解成ABC的形式,其中A,B,C要么<=m,要么是一个素数。

  • 分解素数可以线性筛预处理出每个数的最小质因数d,然后AX,BX,CX可以由AX/d,BX/d,CX/d转移得到

  • Hint

    • 数组要开的小心,因为内存范围限制得很紧

    • 大部分范围用int就可以,除了答案要用unsigned

    • 读入优化的缓存数组开太大会炸掉

代码:

#include <bits/stdc++.h>using namespace std;const int Maxn = 1000010;inline void read(int &x) {    scanf("%d", &x);}int g[1010][1010], p[Maxn / 10], tot, d[Maxn], n, m, A[Maxn], B[Maxn], C[Maxn];bool vis[Maxn];inline void init(int n) {    for (int i = 0; i <= 1005; i++)        for (int j = 0; j <= i; j++) {            if (!i || !j) g[i][j] = i + j;            else g[i][j] = g[j][i % j];        }    for (int i = 0; i <= 1005; i++)        for (int j = i + 1; j <= 1005; j++) g[i][j] = g[j][i];    d[1] = 1;    for (int i = 2; i <= n; i++) {        if (!vis[i]) {            p[++tot] = i;            d[i] = i;        }        for (int j = 1; j <= tot; j++) {            if (i * p[j] > n) break;            vis[i * p[j]] = 1;            if (i % p[j] == 0) {                d[i * p[j]] = d[i];                break;            }            d[i * p[j]] = p[j];        }    }    A[1] = B[1] = C[1] = 1;    for (int i = 2; i <= n; i++) {        int j = i / d[i];        A[i] = A[j], B[i] = B[j], C[i] = C[j];        if (A[i] * d[i] <= 1000) A[i] *= d[i];        else if (B[i] * d[i] <= 1000) B[i] *= d[i];        else C[i] *= d[i];    }}int X[3], c;inline int gcd(int a, int b) {    if (!a || !b) return a + b;    if (a <= 1000 && b <= 1000) return g[a][b];    c = 0; int ans = 1, d = 1;    if (A[a] != 1) X[c++] = A[a];    if (B[a] != 1) X[c++] = B[a];    if (C[a] != 1) X[c++] = C[a];    for (int i = 0; i < c; i++) {        if (X[i] <= 1000) d = g[X[i]][b % X[i]];        else if (b % X[i] == 0) d = X[i];        else d = 1;        ans *= d; b /= d;    }    return ans;}int T, a[2010], b[2010];int main(void) {    //freopen("in.txt", "r", stdin);    init(1000000);    read(T);    while (T--) {        read(n), read(m);        for (int i = 0; i < n; i++) read(a[i]);        for (int i = 0; i < m; i++) read(b[i]);        unsigned int ans = 0;        for (int i = 0; i < n; i++)            for (int j = 0; j < m; j++)                ans += gcd(a[i], b[j]) ^ i ^ j;        printf("%u\n", ans);    }    return 0;}

完。

By g1n0st

0 0