hdu 4676 Sum Of Gcd 莫队+数论

题目链接

 

给n个数, m个询问, 每个询问给出[l, r], 问你对于任意i, j。gcd(a[i], a[j]) L <= i < j <= R的和。

 

假设两个数的公约数有b1, b2, b2...bn, 那么这两个数的最大公约数就是phi[b1] + phi[b2] + phi[b3]...+phi[bn]。

知道这个就可以用莫队了, 具体看代码。

#include <bits/stdc++.h>

using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int mod = 7777777;
const int inf = 1061109567;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
const int maxn = 2e4+3;
vector <int> v[maxn];
struct node
{
    int l, r, block, id;
}q[maxn];
bool cmp(const node& a, const node& b)
{
    if(a.block == b.block)
        return a.r < b.r;
    return a.block < b.block;
}
int phi[maxn], cnt[maxn], a[maxn];
ll res, ans[maxn];
void add(int x)
{
    for(int i = 0; i < v[x].size(); i++) {
        res += phi[v[x][i]]*(cnt[v[x][i]]++);
    }
}
void sub(int x)
{
    for(int i = 0; i < v[x].size(); i++) {
        res -= phi[v[x][i]]*(--cnt[v[x][i]]);
    }
}
void solve(int m)
{
    int L = 1, R = 0;
    res = 0;
    mem(cnt);
    for(int i = 0; i < m; i++) {
        while(R < q[i].r) {
            add(a[++R]);
        }
        while(R > q[i].r) {
            sub(a[R--]);
        }
        while(L < q[i].l) {
            sub(a[L++]);
        }
        while(L > q[i].l) {
            add(a[--L]);
        }
        ans[q[i].id] = res;
    }
}
void init()
{
    for(int i = 1; i < maxn; i++) {
        phi[i] = i;
        for(int j = i; j < maxn; j += i) {
            v[j].pb(i);
        }
    }
    for(int i = 2; i < maxn; i++) {
        if(phi[i] == i) {
            for(int j = i; j < maxn; j += i) {
                phi[j] = phi[j]/i*(i-1);
            }
        }
    }
}
int main()
{
    init();
    int t, n, m;
    cin>>t;
    for(int casee = 1; casee <= t; casee++) {
        scanf("%d", &n);
        int BLOCK = sqrt(n*1.0);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        scanf("%d", &m);
        for(int i = 0; i < m; i++) {
            scanf("%d%d", &q[i].l, &q[i].r);
            q[i].block = q[i].l/BLOCK;
            q[i].id = i;
        }
        sort(q, q+m, cmp);
        solve(m);
        printf("Case #%d:\n", casee);
        for(int i = 0; i < m; i++) {
            printf("%lld\n", ans[i]);
        }
    }
}

 

posted on 2016-07-18 21:13  yohaha  阅读(171)  评论(0编辑  收藏  举报

导航