HDU-6102 GCDispower(莫比乌斯函数+树状数组)

来源:互联网 发布:数控锥度编程 编辑:程序博客网 时间:2024/06/10 15:40

传送门:HDU-6102

题解:莫比乌斯函数+树状数组+离线操作

先对查询按R升序排序,从左到右枚举Ak,再枚举A1~Ak-1中Ak的倍数(因为是1~n的全排列,因此总枚举量为nlogn),得到B数组,将B数组中的数都除以Ak,并按照A中的下标从小到大排序,然后只要求B中所有GCD(Bi,Bj)==1(i<j)的二元组个数即可。

求二元组个数可以直接用莫比乌斯函数求得,对于Bi对答案的贡献为cnt[下标大于i且与Bi互质的Bj]*Ak

每次枚举Ak都要更新A1~Ak-1的贡献,因此可以用树状数组维护。总复杂度O(nlog^2n)

#include<bits/stdc++.h>#define FIN freopen("in.txt","r",stdin);using namespace std;typedef long long LL;typedef pair<int, int> PII;const int MX = 1e5 + 5;const int INF = 0x3f3f3f3f;struct Tree {    int n;    vector <LL> T ;    void init (int sz) {        T.clear();        n = sz;        T.resize(n + 1);    }    void add (int x, LL v) {        for (int i = x; i <= n; i += i & -i) T[i] += v;    }    LL sum (int x) {        if (x > n) x = n;        LL ret = 0;        for (int i = x; i > 0; i -= i & -i) ret += T[i];        return ret;    }} te;struct Query {    int l, r, id;    bool operator<(const Query& _A)const {        if (r != _A.r) return r < _A.r;        return l < _A.l;    }} que[MX];struct Array {    int val, index;    bool operator<(const Array& _A)const {        return index < _A.index;    }} A[MX];int sz, vis[MX], arr[MX];bool prime[MX];int mob[MX], p[MX];vector<int> d[MX];int num[MX];void Mobius() {    int pnum = 0;    memset(prime, true, sizeof(prime));    mob[1] = 1;    for(int i = 2; i < MX; i++) {        if(prime[i]) {            p[pnum ++] = i;            mob[i] = -1;        }        for(int j = 0; j < pnum && (LL)i * p[j] < MX; j++) {            prime[i * p[j]] = false;            if(i % p[j] == 0) {                mob[i * p[j]] = 0;                break;            }            mob[i * p[j]] = -mob[i];        }    }}void presolve() {    for (int i = 1; i < MX; i++) {        for (int j = i; j < MX; j += i) {            d[j].push_back(i);        }    }}void solve(int k) { //A数组是Aj,B数组是Ai,i<j    for (int i = 1; i <= sz; i++) {        int t = A[i].val;        for (int j = 0; j < d[t].size(); j++) num[d[t][j]]++;    }    for (int i = 1; i <= sz; i++) {        LL cnt = 0;        int t = A[i].val;        for (int j = 0; j < d[t].size(); j++) num[d[t][j]]--;        for (int j = 0; j < d[t].size(); j++)            cnt += num[d[t][j]] * mob[d[t][j]];        te.add(A[i].index, cnt * k);    }}LL ans[MX];int main() {    //FIN;    Mobius(); presolve();    int T, n, m;    scanf("%d", &T);    while (T--) {        scanf("%d%d", &n, &m);        te.init(n);        for (int i = 1; i <= n; i++) {            scanf("%d", &arr[i]);            vis[i] = 0;        }        for (int i = 1; i <= m; i++) {            scanf("%d%d", &que[i].l, &que[i].r);            que[i].id = i;        }        sort(que + 1, que + m + 1);        vis[arr[1]] = 1; vis[arr[2]] = 2;        for (int i = 1, k = 3; i <= m; i++) {            for (; k <= que[i].r; k++) {                sz = 0;                vis[arr[k]] = k;                for (int x = 2; x * arr[k] <= n; x++) {                    if (vis[x * arr[k]]) {                        A[++sz].val = x;                        A[sz].index = vis[x * arr[k]];                    }                }                sort(A + 1, A + sz + 1);                solve(arr[k]);            }            ans[que[i].id] = te.sum(que[i].r) - te.sum(que[i].l - 1);        }        for (int i = 1; i <= m; i++) printf("%lld\n", ans[i]);    }    return 0;}


阅读全文
0 0
原创粉丝点击