HDU 5468 Puzzled Elena(DFS序+容斥原理)

来源:互联网 发布:闲鱼淘宝小二介入 编辑:程序博客网 时间:2024/05/12 23:49

题目链接:传送门

题意:

给定一棵树,求这个节点的所有子树中包括他本身与它互质的节点的个数。

分析:转自传送门

因为每个数的大小<=100000 这个范围内   2*3*5*7*11*13 *17> 100000 最多只有 6 个素因子。   

当我们知道这个怎么处理以后,我们可以利用dfs序,解决这个问题

我们求当前这个节点的答案时,用容斥搞就是:以这个节点为根的树的大小 - 有1个素因子和他相同的节点个数 + 有2个素因子和他相同的个数 - 有3个素因子和他相同的个数 ....

那么问题来了,我们如何求出有多少个 有1个素因子和他相同的个数,有2个素因子和他相同的个数 ,,,,,

我们维护一个数fac[]数组,fac[i] 代表包含因子i的节点个数。

那么在这颗树中,进入这颗树之前求一下(有1个素因子和他相同的节点个数,有2个素因子和他相同的节点个数.....),离开这颗树的时候再求一下(有1个素因子和他相同的节点个数,有2个素因子和他相同的节点个数.....),他们的差便是我们需要的(子树中的和他有关系的信息)。

到这里,问题就解决了,容斥版的做法 时间复杂度 O(n*2^6 + nlogn) :

代码如下:

#include <bits/stdc++.h>using namespace std;const int maxn = 1e5+10;int fac[maxn];int w[maxn];int ans[maxn];struct Graph{    vector<int >vc[maxn];    void init(){        for(int i=0;i<maxn;i++)            vc[i].clear();    }    void add(int u,int v){        vc[u].push_back(v);    }}G1,G2;void prepare(){    G1.init();    for(int i=2;i<maxn;i++){        if(G1.vc[i].size())            continue;        for(int j=i;j<maxn;j+=i)            G1.add(j,i);    }}int calc(int u,int x){    int ans = 0,n=G1.vc[u].size();    for(int i=1;i<(1<<n);i++){        int tot=1,cnt=0;        for(int j=0;j<n;j++){            if((1<<j)&i){                cnt++;                tot=tot*G1.vc[u][j];            }        }        if(cnt&1)            ans = ans+fac[tot];        else            ans = ans-fac[tot];        fac[tot]+=x;    }    return ans;}int dfs(int u,int pre){    int cnt = 0;    int L = calc(w[u],0);    for(int i=0;i<G2.vc[u].size();i++){        int v = G2.vc[u][i];        if(v==pre) continue;        cnt+=dfs(v,u);    }    int R = calc(w[u],1);    ans[u]=cnt-(R-L);    if(w[u]==1) ans[u]++;    return cnt+1;}int main(){    prepare();    int n,cas=1;    while(~scanf("%d",&n)){        G2.init();        memset(fac,0,sizeof(fac));        int u,v;        for(int i=1;i<n;i++){            scanf("%d%d",&u,&v);            G2.add(u,v);            G2.add(v,u);        }        for(int i=1;i<=n;i++)            scanf("%d",w+i);        dfs(1,0);        printf("Case #%d: ",cas++);        for(int i=1;i<=n;i++){            printf("%d%c",ans[i],i==n? '\n':' ');        }    }    return 0;}



1 0
原创粉丝点击