【HDU - 5468 】Puzzled Elena(容斥)

本文探讨了一道关于树形结构的算法问题,利用深度优先搜索(DFS)结合容斥原理,解决如何在树中寻找互质顶点数量的问题。通过预处理每个数的平方自由数(square-free number)和莫比乌斯函数,实现了高效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Since both Stefan and Damon fell in love with Elena, and it was really difficult for her to choose. Bonnie, her best friend, suggested her to throw a question to them, and she would choose the one who can solve it.

Suppose there is a tree with n vertices and n - 1 edges, and there is a value at each vertex. The root is vertex 1. Then for each vertex, could you tell me how many vertices of its subtree can be said to be co-prime with itself?
NOTES: Two vertices are said to be co-prime if their values’ GCD (greatest common divisor) equals 1.
Input
There are multiply tests (no more than 8).
For each test, the first line has a number n (1n1051≤n≤105), after that has n−1 lines, each line has two numbers a and b (1a,bn)(1≤a,b≤n), representing that vertex a is connect with vertex b. Then the next line has n numbers, the ith number indicates the value of the ith vertex. Values of vertices are not less than 11 and not more than 105.
Output
For each test, at first, please output “Case #k: “, k is the number of test. Then, please output one line with n numbers (separated by spaces), representing the answer of each vertex.
Sample Input
5
1 2
1 3
2 4
2 5
6 2 3 4 5
Sample Output
Case #1: 1 1 0 0 0
思路:当时做这题的idea其实是联想到今年山东acm省赛热身赛的B题(当时做掉这题,我们的rank就直接到第5了,在正赛造了报应,,,),我们先考虑一个问题,先解决如何在一堆整数集合当中找到互质的个数,可以考虑枚举,但是在树上做这个必然会T,我换了一个角度而是去观察每个数具有什么属性,这个就是容斥,属性的个数是有多少个sqare-free number是他的因子。极端情况是26126−1个,即这个数是235711132∗3∗5∗7∗11∗13的连乘,这种情况是最坏的情况,复杂度虽然O(n)O(n),但是常数就很大,但是目测还是可以过掉,优化的地方是因为case稍多,所以可以预处理一下每个数的sqare-free number,可以筛一下莫比乌斯函数来做,同时也需要莫比乌斯函数来容斥答案。
代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#define ll long long
#define maxx 100005
using namespace std;
vector<int> fac[maxx];
int mu[maxx];
bool p[maxx];
int prime[maxx],cnt;
void init()
{
    p[1]=mu[1]=1;
    for(int i=2;i<maxx;i++)
    {
        if(!p[i])
        {
            prime[cnt++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<cnt&&i*prime[j]<=maxx;j++)
        {
            p[i*prime[j]]=true;
            if(i%prime[j])
                mu[i*prime[j]]=-mu[i];
            else
            {
                mu[i*prime[j]]=0;
                break;
            }
        }
    }
    for(int i=2;i<maxx;i++)
    {
        if(mu[i]==0)continue;
        for(int j=i;j<maxx;j+=i)
            fac[j].push_back(i);
    }
}
int head[maxx],to[maxx<<1],_next[maxx<<1],edge;
int c[maxx];
void addEdge(int x, int y)
{
    to[++edge]=y,_next[edge]=head[x],head[x]=edge;
    to[++edge]=x,_next[edge]=head[y],head[y]=edge;
}
int n;
int a[maxx];
int total;
int ans[maxx];
void dfs(int u,int fa)
{
    int num=a[u];
    int temp=total;
    for(int i=0;i<fac[num].size();i++)
    {
        if(mu[fac[num][i]]==-1)temp-=c[fac[num][i]];
        else temp+=c[fac[num][i]];
    }
    for(int i=head[u];i;i=_next[i])
    {
        int v=to[i];
        if(v==fa)continue;
        dfs(v,u);
    }
    ++total;
    for(int i=0;i<fac[num].size();i++) ++c[fac[num][i]];
    ans[u]=total;
    for(int i=0;i<fac[num].size();i++)
    {
        int _fac=fac[num][i];
        if(mu[_fac]==-1)ans[u]-=c[_fac];
        else ans[u]+=c[_fac];
    }

    ans[u]-=temp;
}
void _init()
{
    total=0;
    edge=0;
    memset(head,0,sizeof(head));
    memset(c,0,sizeof(head));

}
int main()
{
    init();
    int cal=1;
    int x,y;
    while(scanf("%d",&n)==1)
    {
        _init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            addEdge(x,y);
        }
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        dfs(1,0);
        printf("Case #%d:",cal++);
        for(int i=1;i<n;i++)printf(" %d",ans[i]);
        printf(" %d\n",ans[n]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值