做了好几个容斥了,一直找不到feel,这个做完在现在有一点感觉了。虽然刚开始也不会。但就是发现感觉不一样了。

首先,不考虑树的关系,单纯给出一个m,还有一个集合(里面数字任意),求集合里面跟m互质的数的个数。这就是典型的容斥题。

那么现在要求得使顶点跟子节点的互质关系,那么原理还是有容斥喽,还是回到一开始那个问题,如何计算跟m互质的数的个数,做法是将m进行质因子分解,然后计算集合中有多少能被m的因子整除,然后容斥加加减减即可。那么对于树,可以采用dfs递归求解。预处理每个数的素因子,在递归过程中计算x顶点的所有子节点的含有因子Y的集合中元素的个数,然后容斥计算即可。但在递归过程中要记录下一步计算的过程中用到的因子在之前一共出现了多少次,最后算的时候计算差值即可。代码不是很难,直接看也能理解。就是那个pre数组用的有点巧妙。

#include<bits/stdc++.h>using namespace std;const int maxn=1e5+10;int prime[maxn],cnt;
bool vis[maxn];vector<int> f[maxn];void get_prime_fac(){for(int i=2;i<maxn;i++){if(!vis[i]){prime[cnt++]=i;for(int j=i;j<maxn;j+=i){f[j].push_back(i);vis[j]=1;}}}
}vector<int> g[maxn];
int val[maxn];
int ans[maxn];
int st[maxn];
int en[maxn];
int a[maxn];    //a[x]代表保存该x顶点的子树的因子个数。
int dfs_clock;int facnum;
vector<int> fac;inline void get_fac(int x){fac=f[x];facnum=fac.size();
}inline void add(int x){get_fac(val[x]);for(int i=1;i<(1<<facnum);i++){int tmp=1;for(int j=0;j<facnum;j++){if(i&(1<<j))tmp*=fac[j];}a[tmp]++;}
}void dfs(int x,int fa){int pre[100];st[x]=++dfs_clock;get_fac(val[x]);for(int i=1;i<(1<<facnum);i++){int tmp=1;for(int j=0;j<facnum;j++){if(i&(1<<j)){tmp*=fac[j];}}pre[i]=a[tmp];      //保存tmp因子出现之前对应的数量,拿x顶点为例的话,左子树会对计算右子树会产生影响。}for(int i=0;i<g[x].size();i++){int v=g[x][i];if(v==fa) continue;dfs(v,x);}en[x]=dfs_clock;get_fac(val[x]);ans[x]=en[x]-st[x];for(int i=1;i<(1<<facnum);i++){int tmp=1,cnt=0;for(int j=0;j<facnum;j++){if(i&(1<<j)){tmp*=fac[j];cnt^=1;}}if(cnt) ans[x]-=(a[tmp]-pre[i]);else ans[x]+=(a[tmp]-pre[i]);}add(x);if(val[x]==1) ans[x]++; //这是一个特别注意的地方。
}int main(){get_prime_fac();int n,cs=1;while(~scanf("%d",&n)){for(int i=1;i<=n;i++){g[i].clear();}for(int i=1;i<n;i++){int u,v;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(a,0,sizeof a);dfs_clock=0;dfs(1,-1);printf("Case #%d:",cs++);for(int i=1;i<=n;i++){printf(" %d",ans[i]);}printf("\n");}
}

使用莫比乌斯反演,其实写下容斥的计算式子,可以发现其容斥系数其实就是莫比乌斯函数

所以集合中跟m不互素的数的个数

count函数表示集合中出现因子d的元素的个数。

#include<bits/stdc++.h>using namespace std;const int maxn=1e5+10;int mu[maxn],cnt,prime[maxn];
bool vis[maxn];vector<int> f[maxn];void get_mu_fac(){memset(vis,0,sizeof vis);mu[1]=1;int tot=0;for(int i=2;i<maxn;i++){if(!vis[i]){prime[tot++]=i;mu[i]=-1;}for(int j=0;j<tot;j++){if(i*prime[j]>=maxn) break;vis[i*prime[j]]=1;if(i%prime[j]==0){mu[i*prime[j]]=0;break;}else{mu[i*prime[j]]=-mu[i];}}}for(int i=2;i<maxn;i++){if(mu[i]!=0){for(int j=i;j<maxn;j+=i){f[j].push_back(i);}}}
}vector<int> g[maxn];
int val[maxn];
int ans[maxn];
int st[maxn];
int en[maxn];
int a[maxn];    //a[x]代表保存该x顶点的子树的因子个数。
int dfs_clock;int facnum;
vector<int> fac;inline void get_fac(int x){fac=f[x];facnum=fac.size();
}void dfs(int x,int fa){int pre[100];st[x]=++dfs_clock;get_fac(val[x]);for(int i=0;i<facnum;i++){pre[i]=a[fac[i]];      //保存tmp因子出现之前对应的数量,拿x顶点为例的话,左子树会对计算右子树会产生影响。}for(int i=0;i<g[x].size();i++){int v=g[x][i];if(v==fa) continue;dfs(v,x);}en[x]=dfs_clock;get_fac(val[x]);ans[x]=en[x]-st[x];for(int i=0;i<facnum;i++){int sum=a[fac[i]]-pre[i];ans[x]+=mu[fac[i]]*sum;}for(int i=0;i<facnum;i++){a[fac[i]]++;}if(val[x]==1) ans[x]++; //这是一个特别注意的地方。
}int main(){get_mu_fac();int n,cs=1;while(~scanf("%d",&n)){for(int i=1;i<=n;i++){g[i].clear();}for(int i=1;i<n;i++){int u,v;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(a,0,sizeof a);dfs_clock=0;dfs(1,-1);printf("Case #%d:",cs++);for(int i=1;i<=n;i++){printf(" %d",ans[i]);}printf("\n");}
}

HDU - 5468 Puzzled Elena (容斥/莫比乌斯)相关推荐

  1. HDU - 5468 Puzzled Elena —— 容斥

    题意: 每个点的子树上有几个节点与该节点的权值互质 思路: 首先要明白怎么求一个集合中有多少个数与n互素 将集合中的数用算术基本定理分解,记录每个数能形成的所有因子的个数,然后将n分解进行容斥,可以求 ...

  2. hdu5468 Puzzled Elena(容斥 莫比乌斯反演)

    hdu5468 Puzzled Elena 题意 求一棵子树内与它互质的点个数 解法 容斥 我们先求出与它不互质的数的个数,再用总数减去就好. #include <cstdio> #inc ...

  3. hdu 5468 Puzzled Elena(前缀性质+dfs序+容斥)

    题目链接:hdu 5468 Puzzled Elena 解题思路 预处理出每个数的因子(注意只需要质因子幂数最大为1的数,例如6=21∗316=2^1 * 3^1)然后用一个数组维护,fac[i]表示 ...

  4. hdu 5468 Puzzled Elena

    一颗大小为(n<=100000) 的树,根为1,每个节点有个权值.问:每个节点 和 以这个节点为根的子树中 有多少权值和根的权值互质. 做法,我们首先要明白一个东西,就是当你已经知道了k个数,并 ...

  5. HDU 5468 Puzzled Elena 莫比乌斯反演

    题意: 给出一棵树,每个点上有权值.然后求每棵子树中与根节点互质( \(gcd(a, b) = 1\) )的节点个数. 分析: 对于一颗子树来说,设根节点的权值为\(u\), \(count_i\)表 ...

  6. HDU 5468 Puzzled Elena(2015 ACM/ICPC Asia Regional Shanghai Online)

    题目大意 这道题要求出每个节点与其子树节点中有多少个节点互质,题目是这样,但是如果你认为真的是这样那就错了,因为有可能根节点是1,那么1与本身也是互质的!!其实我真的搞不懂,说好了与子树互质为什么就把 ...

  7. 【HDU】5468 Puzzled Elena

    Puzzled Elena 题目链接 Puzzled Elena 题目大意 给你一棵树,n个节点n-1条边,每个节点都有一个权值.现在让你求每个节点的子树下面有多少个节点与该节点互质. 题解 容斥原理 ...

  8. bzoj2440 [中山市选2011]完全平方数 容斥+莫比乌斯函数

    Description 小 X 自幼就很喜欢数.但奇怪的是,他十分讨厌完全平方数.他觉得这些 数看起来很令人难受.由此,他也讨厌所有是完全平方数的正整数倍的数.然而 这丝毫不影响他对其他数的热爱. 这 ...

  9. CodeForces 1139D Steps to One(概率dp 容斥/莫比乌斯反演)

    题目链接https://codeforces.com/contest/1139/problem/D 题意:给定一个m,每次在1-m中随机取一个数放到容器中,当容器的gcd为1时停止,求期望步数,用分数 ...

最新文章

  1. 公众号群发文章支持添加小程序
  2. 阿里巴巴电商搜索推荐实时数仓演进之路
  3. 将图片资源文件整合到DLL文件中
  4. 【Qt笔记】对象模型
  5. [Math][Algebra]--线性代数中的各种空间
  6. Skype一国通套餐不再提供无限制拨打中国大陆地区通知
  7. 空中交警:借你一双“慧眼”,让你看透这飞机的“黑色十分钟”
  8. java 单选下拉_jQuery对单选框radio,复选框checkbox,下拉列表select的操作
  9. 使用Jenkins在Azure Web App上进行ASP.NET Core应用程序的持续集成和部署(CI/CD)–第3天
  10. 4后期盒子叫什么_考研:什么叫跨考专业?跨考专业的4大原因和存在3个方面的困难...
  11. 希望博客园可以开个邮件列表
  12. ResNet卷积神经网络
  13. 在Windows下的路径分隔符和Linux下的路径分隔符是不一样的
  14. “一键淘宝”将淘宝网店免费转移到手机客户端教程
  15. Android性能优化之内存优化
  16. 中国人民大学与加拿大女王大学金融硕士——在这里,打开精彩“识界”
  17. canvas-绘制背景
  18. wx网罗系列之翔实:使用C++开发wxWidgets程序
  19. Hadoop完全分布式安装教程
  20. Python爬虫+数据可视化教学:分析猫咪交易数据

热门文章

  1. 90后的你现在拥有了多少存款?
  2. c语言终极面试宝典 pdf,C语言终极面试宝典_C语言面试必备
  3. python文字验证码识别_利用python进行验证码识别(预处理部分)
  4. java程序 图形界面_java 图形程序
  5. 由程控交换机组成的呼叫中心系统
  6. 网络电话变身情趣APP 体验通话更多乐趣
  7. 小天才网络adb_小天才电话手表拨号盘代码大全 又快又好
  8. linux编译fdk aac,使用NDK编译ffmpeg4.1+fdk-aac2.0
  9. matlab绘制色盘色调混合模式
  10. Appium元素定位和案例(有注释)