zoukankan      html  css  js  c++  java
  • HDU 5468 Puzzled Elena 莫比乌斯反演

    题意:

    给出一棵树,每个点上有权值.然后求每棵子树中与根节点互质( (gcd(a, b) = 1) )的节点个数.

    分析:

    对于一颗子树来说,设根节点的权值为(u), (count_i)表示权值为(i)的倍数的节点的个数.

    那么根据莫比乌斯反演,与(u)互质的节点的个数为(sum_{d|u}mu(d)count_d)

    所以,我们记录一下遍历子树之前的(count)值和遍历子树之后的(count)值,作差就是这棵子树的(count)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    
    const int maxn = 100000;
    
    int mu[maxn + 10], pcnt, prime[maxn];
    bool vis[maxn + 10];
    vector<int> factors[maxn + 10];
    vector<int> G[maxn + 10];
    
    void preprocess() {
        pcnt = 0;
        mu[1] = 1;
        for(int i = 2; i <= maxn; i++) {
            if(!vis[i]) {
                mu[i] = -1;
                prime[pcnt++] = i;
            }
            for(int j = 0; j < pcnt && i * prime[j] <= maxn; j++) {
                vis[i * prime[j]] = true;
                if(i % prime[j] != 0) mu[i * prime[j]] = -mu[i];
                else {
                    mu[i * prime[j]] = 0;
                    break;
                }
            }
        }
    
        for(int i = 2; i <= maxn; i++) if(mu[i])
            for(int j = i; j <= maxn; j += i) factors[j].push_back(i);
    }
    
    int val[maxn + 10];
    int n;
    
    int cnt[maxn], sz[maxn], ans[maxn];
    
    void dfs(int u, int fa) {
        sz[u] = 1;
        vector<int> pre;
        for(int d : factors[val[u]]) {
            pre.push_back(cnt[d]);
            cnt[d]++;
        }
        for(int v : G[u]) {
            if(v == fa) continue;
            dfs(v, u);
            sz[u] += sz[v];
        }
        ans[u] = sz[u];
        for(int i = 0; i < factors[val[u]].size(); i++) {
            int d = factors[val[u]][i];
            int c = cnt[d] - pre[i];
            if(c) ans[u] += mu[d] * c;
        }
    }
    
    int main()
    {
        preprocess();
    
        int kase = 1;
        while(scanf("%d", &n) == 1 && n) {
            for(int i = 1; i <= n; i++) G[i].clear();
    
            for(int u, v, i = 1; i < n; i++) {
                scanf("%d%d", &u, &v);
                G[u].push_back(v);
                G[v].push_back(u);
            }
            for(int i = 1; i <= n; i++) scanf("%d", val + i);
    
            memset(cnt, 0, sizeof(cnt));
            dfs(1, 0);
    
            printf("Case #%d:", kase++);
            for(int i = 1; i <= n; i++) printf(" %d", ans[i]);
            printf("
    ");
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    C#CreateGraphics方法的三种实现方式
    二叉树的性质和常用操作代码集合
    《Java程序设计基础》 第8章手记Part 2
    《Java程序设计基础》 第8章手记Part 1
    STL 算法罗列 (转)
    STL 练习
    STL所有算法简介 (转) http://www.cnblogs.com/yuehui/archive/2012/06/19/2554300.html
    linux 解压命令
    杭电1016
    杭电1257
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4858452.html
Copyright © 2011-2022 走看看