题目描述

Problem description.
You are given a tree. If we select 2 distinct nodes uniformly at random, what’s the probability that the distance between these 2 nodes is a prime number?
Input
The first line contains a number N: the number of nodes in this tree.
The following N-1 lines contain pairs a[i] and b[i], which means there is an edge with length 1 between a[i] and b[i].
Output
Output a real number denote the probability we want.
You’ll get accept if the difference between your answer and standard answer is no more than 10^-6.
Constraints
2 ≤ N ≤ 50,000
The input must be a tree.
Example
Input:
5
1 2
2 3
3 4
4 5
Output:
0.5
Explanation
We have C(5, 2) = 10 choices, and these 5 of them have a prime distance:
1-3, 2-4, 3-5: 2
1-4, 2-5: 3
Note that 1 is not a prime number.

题目分析

使用树分治后我们能够得到任意点到重心的距离,现在问题转换为如何判断两点之间的距离为素数。

首先我们要使用线性筛处理出一个素数表。

一个简单的想法是我们将Dis数组中不同的点加起来就是不同两点之间的距离。然后再判断这个距离是不是素数,如果是素数则将路径+1。可是这样时间复杂度太高(O(n*n)),因此我们需要使用FFT进行加速,快速得到两路径的和。但是我们需要减去同一条路径走两边的情况。

需要求概率,我们就需要知道事件数是什么。对于这里来讲,我们需要考虑的是选择排列还是组合。由给出的样例我们看出,应该按照组合进行计算。因此对于每个路径和我们都应该/2,这样得到的才是排列数。

需要注意的是每次FFT以后对数组的清零。我就是这里没有注意然后导致疯狂出错,还一直检查不出问题。

还有就是,树上的路径很多,很容易long long

AC代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<cmath>using namespace std;const int MAXN=5e5+5;
const double PI=acos(-1.0);
typedef long long ll;
struct edge
{int to,len,last;
}Edge[MAXN<<2]; int Last[MAXN],tot;
int n,kk,SonNum[MAXN],MaxNum[MAXN],Vis[MAXN],Dis[MAXN];
int Prime[MAXN]; bool IsPrime[MAXN]; int prime_num=0;
int root,rootx,dlen,ss;
ll Num[MAXN<<2],MaxLen,len;
ll Res[MAXN<<2];
ll ans;struct complex
{double r,i;complex(double _r=0,double _i=0):r(_r),i(_i){}complex operator +(const complex &b) {return complex(r+b.r,i+b.i);}complex operator -(const complex &b) {return complex(r-b.r,i-b.i);}complex operator *(const complex &b) {return complex(r*b.r-i*b.i,r*b.i+i*b.r);}
}A[MAXN<<2];void change(complex y[],int len)
{int i,j,k;for(i = 1, j = len/2;i < len-1;i++){if(i < j)swap(y[i],y[j]);k = len/2;while( j >= k){j -= k;k /= 2;}if(j < k)j += k;}
}void fft(complex y[],int len,int on)
{change(y,len);for(int h = 2;h <= len;h <<= 1){complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));for(int j = 0;j < len;j += h){complex w(1,0);for(int k = j;k < j+h/2;k++){complex u = y[k];complex t = w*y[k+h/2];y[k] = u+t;y[k+h/2] = u-t;w = w*wn;}}}if(on == -1)for(int i = 0;i < len;i++)y[i].r /= len;
}void FFT(ll a[],int la,ll b[])//la,lb分别是a,b数组的最高位+1
{//int len=1; while(len<la+la) len<<=1;for(int i=0;i<la;++i) A[i]=complex(a[i],0);for(int i=la;i<len;++i) A[i]=complex(0,0);fft(A,len,1);for(int i=0;i<len;++i) A[i]=A[i]*A[i];fft(A,len,-1);for(int i=0;i<len;++i) b[i]=(ll)(A[i].r+0.5);
}void CreatPrime()
{IsPrime[0]=IsPrime[1]=true; prime_num=0;for(int i=2;i<MAXN;++i){if(!IsPrime[i])Prime[prime_num++]=i;for(int j=0;j<prime_num && Prime[j]*i<MAXN;j++){IsPrime[Prime[j]*i]=true;if(i%Prime[j]==0) break;}}
}int getint()
{int x=0,sign=1; char c=getchar();while(c<'0' || c>'9'){if(c=='-') sign=-1; c=getchar();}while(c>='0' && c<='9'){x=x*10+c-'0'; c=getchar();}return x*sign;
}void Init()
{//CreatPrime();//for(int i=0;i<=n;++i) Last[i]=0; memset(Last,-1,sizeof(Last));tot=0;ans=0;
}void Clear()
{for(int i=0;i<=n;++i) Vis[i]=false;
}void AddEdge(int u,int v,int w)
{Edge[++tot].to=v; Edge[tot].len=w; Edge[tot].last=Last[u]; Last[u]=tot;
}void Read()
{n=getint();int u,v;for(int i=1;i<n;i++){u=getint(); v=getint();AddEdge(u,v,1); AddEdge(v,u,1);}
}void GetRoot(int x,int father)
{int v;SonNum[x]=1; MaxNum[x]=1;for(int i=Last[x];~i;i=Edge[i].last){v=Edge[i].to; if(v==father || Vis[v]) continue;GetRoot(v,x);SonNum[x]+=SonNum[v];if(SonNum[v]>MaxNum[x]) MaxNum[x]=SonNum[x];}if(ss-SonNum[x]>MaxNum[x]) MaxNum[x]=ss-SonNum[x];if(rootx>MaxNum[x]) root=x,rootx=MaxNum[x];
}void GetDis(int x,int father,int dis)
{int v;Dis[++dlen]=dis;for(int i=Last[x];~i;i=Edge[i].last){v=Edge[i].to; if(v==father|| Vis[v]) continue;GetDis(v,x,dis+Edge[i].len);}
}ll Count(int x,int dis)
{ll ret=0;for(int i=0;i<=dlen;++i) Dis[i]=0;dlen=0;GetDis(x,0,dis);/*for(int i=1;i<=dlen;++i)for(int j=i+1;j<=dlen;++j){if(!IsPrime[Dis[i]+Dis[j]]) ++ret;}*///memset(Num,0,sizeof(Num));MaxLen=0;for(int i=1;i<=dlen;++i){++Num[Dis[i]]; if(Dis[i]>MaxLen) MaxLen=Dis[i];}len=1; while(len<=2*MaxLen) len<<=1;FFT(Num,MaxLen+1,Res);for(int i=1;i<=dlen;++i){--Res[Dis[i]+Dis[i]];}MaxLen<<=1;for(int i=0;i<=len;++i){Res[i]/=2;}for(int i=0;i<prime_num && Prime[i]<=MaxLen;++i){ret+=Res[Prime[i]];}for(int i=1;i<=dlen;++i){Num[Dis[i]]=0;}return ret;
}void Solve(int x)
{int v;ans+=Count(x,0);Vis[x]=true;for(int i=Last[x];~i;i=Edge[i].last){v=Edge[i].to; if(Vis[v]) continue;ans-=Count(v,Edge[i].len);ss=SonNum[v]; rootx=INT_MAX; root=0;GetRoot(v,x);Solve(root);}
}void Work()
{rootx=INT_MAX; ss=n; root=0;GetRoot(1,0); Solve(root);
}void Write()
{ll tmp=(ll)n*(n-1)/2;//printf("%.f\n",tmp);printf("%.7f\n",(double)ans/tmp);}int main()
{CreatPrime();//while(~scanf("%d",&n))//{Init();Read();Work();Write();Clear();//}return 0;
}

Prime Distance On Tree-树分治+FFT相关推荐

  1. POJ 1741 Tree 树分治

    题意: 给出一颗有\(n (n \leq 10^4)\)个节点的树,和一个\(k\).统计有多少个点对\(u, \, v(u \neq v)\)满足\(u\)到\(v\)的最短距离不超过\(k\). ...

  2. POJ 1741 Tree(树分治)

    去网上搜题解大多数都是说论文,搜了论文看了看,写的确实挺好,直接复制过来. 不过代码中有些细节还是要注意的,参考这篇http://blog.sina.com.cn/s/blog_6d5aa19a010 ...

  3. Tree(树分治入门)

    题目链接:http://poj.org/problem?id=1741 Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions ...

  4. POJ1741 Tree(树分治——点分治)题解

    题意:给一棵树,问你最多能找到几个组合(u,v),使得两点距离不超过k. 思路:点分治,复杂度O(nlogn*logn).看了半天还是有点模糊. 显然,所有满足要求的组合,连接这两个点,他们必然经过他 ...

  5. POJ1741:Tree——题解+树分治简要讲解

    http://poj.org/problem?id=1741 题目大意:给一棵树,求点对间距离<=k的个数. -------------------- 以这道题为例记录一下对于树分治的理解. 树 ...

  6. POJ1741 Tree 树中点对统计【树分治入门】

    算法合集之<分治算法在树的路径问题中的应用> 论文下载地址 树被定义为没有圈的连通图,有几个性质 在树中去掉一条边后,得到的图是不连通的 在树中添加一条边后,一定存在一条边 树的每一对顶点 ...

  7. 【楼天城男人八题】【树分治|Treap+启发式合并】POJ1741 Tree

    题面在这里 待我先膜拜一下楼教主-- 首先这题是很明显的树分治 想说点什么却发现已经没什么好说了 然后我们来看另一种解法:平衡树乱搞 这里用的是Treap实现 对于每个节点,用Treap记录该子树每个 ...

  8. [分治FFT]「CTSC2018」青蕈领主

    题目梗概 定义一个序列是连续的,当且仅当这个序列的最大值-最小值不超过序列长度-1. 现在有一个长度为\(n\)的排列,给出以每个位置为右端点的最长连续区间的长度,求满足的排列的方案数. 解题思路 如 ...

  9. 树分治树链剖分相关题目讨论

    预备知识 树分治,树链剖分 poj1741 •一棵有n个节点的树,节点之间的边有长度.方方方想知道,有多少个点对距离不超过m 题解 点分治模板题.详见我早上写的http://www.cnblogs.c ...

最新文章

  1. eclipse假死解决办法
  2. SpringBoot整合Druid数据源
  3. 大数据时代最值得关注的15大技术趋势
  4. 拳王虚拟项目公社:闲鱼操作虚拟资源的案例拆解,教你玩转闲鱼虚拟资源,货源+方法
  5. ppa java 8_通过 ppa 在ubuntu server 上安装java 8
  6. spring 操作对象写入mongo去除_class列
  7. 基于LabVIEW的个性化打地鼠游戏设计
  8. umijs有什么好处_UmiJS
  9. 慕课课程《简明世界史》课堂笔记二
  10. 18位身份证的正则表达式并说明
  11. PDF如何删除页面?批量删除不连续页的方法
  12. dataframe排序 pd.rank()
  13. 2020少儿编程教育政策大汇总!
  14.  一套莫尔斯电报听写、翻译系统
  15. win10 运行debug程序
  16. 《软件体系结构》习题解答(二)
  17. HTML5新特性小结
  18. 论坛,贴吧,Q群,微信个人号群发
  19. 第一章 管理与管理学 第一节 笔记2018
  20. 如何参与github开源项目,成为contributor

热门文章

  1. Struts2 自定义拦截器(easy example)
  2. QT mainwindow四件套
  3. c#获取系统时间的方法
  4. 从MySQL导入导出大量数据的程序实现方法
  5. android根据拍摄url获取格式,Android如何通过URI获取文件路径示例代码
  6. 骁龙660是32位还是64位_高通发布骁龙 7c/8c 芯片,以后你可能会在电脑上看到它...
  7. java21个知识点重点_java21个知识点重点
  8. java 向父类_Java基础——面向对象(Object父类)
  9. php 状态码302,HTTP状态码302、303和307的故事
  10. 索引和未索引执行计划的比较_详解Oracle复合索引+实例说明