GCD

来源:互联网 发布:单片机培训机构 编辑:程序博客网 时间:2024/05/16 00:36

GCD

这里写图片描述
这里写图片描述
.
.
题意:给n个数,q次询问,问l到r之间的数的gcd的值为多少,并输出序列中所有(l<=r)的子序列中,有多少对的gcd值为询问的值
.
.
解法:因为数越多,gcd值的数越小,可以用map先预处理第二问,然后第一问可以用线段树处理。
.
.

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <algorithm>#include <map>#include <string.h>using namespace std;int tree[2500000], n, m, t, x, y, k;map<int, long long> f[200000], ans;int gcd(int x, int y) {    while (1) {        int temp = x%y;        x = y;        y = temp;        if (y == 0) break;    }    return x;}void insert(int x, int l, int r, int pos, int val) {    if (l == r) {        tree[x] = val;        return;    }    int mid = (l+r)>>1;    if (pos <= mid) {        insert(x<<1, l, mid, pos, val);        if (tree[x] == 0) tree[x] = tree[x<<1];        else tree[x] = gcd(tree[x], tree[x<<1]);    } else {        insert(x<<1|1, mid+1, r, pos, val);        if (tree[x] == 0) tree[x] = tree[x<<1|1];        else tree[x] = gcd(tree[x], tree[x<<1|1]);    }}int find(int x, int l, int r, int ll, int rr) {    if (l == ll && r == rr) {        return tree[x];    }    int mid = (l+r)>>1;    if (rr <= mid) {        int temp = find(x<<1, l, mid, ll, rr);        return temp;    } else if (ll >= mid+1) {        int temp = find(x<<1|1, mid+1, r, ll, rr);        return temp;    } else {        int temp1 = find(x<<1, l, mid, ll, mid);        int temp2 = find(x<<1|1, mid+1, r, mid+1, rr);        return (gcd(temp1, temp2));    }}int main() {    freopen("d.in","r",stdin);    int tt;    scanf("%d", &tt);    int cases = 0;    while (tt--) {        cases++;        scanf("%d", &n);        ans.clear();        memset(tree, 0, sizeof(tree));        for (int i = 1; i <= n; i++) {            scanf("%d", &x);            insert(1, 1, n, i, x);            f[i].clear();            f[i][x] = 1;            if (!ans[x]) ans[x] = 1;            else ans[x] = ans[x]+1;            if (i != 1)            for (map<int, long long>::iterator ii = f[i-1].begin(); ii != f[i-1].end(); ii++) {                int temp = gcd(ii->first, x);                if (!f[i][temp]) f[i][temp] = f[i-1][ii->first];                else f[i][temp] = f[i][temp]+f[i-1][ii->first];                if (!ans[temp]) ans[temp] = f[i-1][ii->first];                else ans[temp] = ans[temp]+f[i-1][ii->first];            }        }        /*        for (int i = 1; i <= n; i++) {            printf("%d : \n", i);            for (map<int, long long>::iterator ii = f[i].begin(); ii != f[i].end(); ii++) {                printf("\t%d %lld\n", ii->first, ii->second);            }        }        */        printf("Case #%d:\n", cases);        scanf("%d", &m);        for (int i = 1; i <= m; i++) {            scanf("%d %d", &x, &y);            if (x > y) swap(x, y);            t = find(1, 1, n, x, y);            printf("%d %lld\n", t, ans[t]);        }    }}
0 0