Prime Distance On Tree-树分治+FFT
题目描述
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相关推荐
- POJ 1741 Tree 树分治
题意: 给出一颗有\(n (n \leq 10^4)\)个节点的树,和一个\(k\).统计有多少个点对\(u, \, v(u \neq v)\)满足\(u\)到\(v\)的最短距离不超过\(k\). ...
- POJ 1741 Tree(树分治)
去网上搜题解大多数都是说论文,搜了论文看了看,写的确实挺好,直接复制过来. 不过代码中有些细节还是要注意的,参考这篇http://blog.sina.com.cn/s/blog_6d5aa19a010 ...
- Tree(树分治入门)
题目链接:http://poj.org/problem?id=1741 Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions ...
- POJ1741 Tree(树分治——点分治)题解
题意:给一棵树,问你最多能找到几个组合(u,v),使得两点距离不超过k. 思路:点分治,复杂度O(nlogn*logn).看了半天还是有点模糊. 显然,所有满足要求的组合,连接这两个点,他们必然经过他 ...
- POJ1741:Tree——题解+树分治简要讲解
http://poj.org/problem?id=1741 题目大意:给一棵树,求点对间距离<=k的个数. -------------------- 以这道题为例记录一下对于树分治的理解. 树 ...
- POJ1741 Tree 树中点对统计【树分治入门】
算法合集之<分治算法在树的路径问题中的应用> 论文下载地址 树被定义为没有圈的连通图,有几个性质 在树中去掉一条边后,得到的图是不连通的 在树中添加一条边后,一定存在一条边 树的每一对顶点 ...
- 【楼天城男人八题】【树分治|Treap+启发式合并】POJ1741 Tree
题面在这里 待我先膜拜一下楼教主-- 首先这题是很明显的树分治 想说点什么却发现已经没什么好说了 然后我们来看另一种解法:平衡树乱搞 这里用的是Treap实现 对于每个节点,用Treap记录该子树每个 ...
- [分治FFT]「CTSC2018」青蕈领主
题目梗概 定义一个序列是连续的,当且仅当这个序列的最大值-最小值不超过序列长度-1. 现在有一个长度为\(n\)的排列,给出以每个位置为右端点的最长连续区间的长度,求满足的排列的方案数. 解题思路 如 ...
- 树分治树链剖分相关题目讨论
预备知识 树分治,树链剖分 poj1741 •一棵有n个节点的树,节点之间的边有长度.方方方想知道,有多少个点对距离不超过m 题解 点分治模板题.详见我早上写的http://www.cnblogs.c ...
最新文章
- eclipse假死解决办法
- SpringBoot整合Druid数据源
- 大数据时代最值得关注的15大技术趋势
- 拳王虚拟项目公社:闲鱼操作虚拟资源的案例拆解,教你玩转闲鱼虚拟资源,货源+方法
- ppa java 8_通过 ppa 在ubuntu server 上安装java 8
- spring 操作对象写入mongo去除_class列
- 基于LabVIEW的个性化打地鼠游戏设计
- umijs有什么好处_UmiJS
- 慕课课程《简明世界史》课堂笔记二
- 18位身份证的正则表达式并说明
- PDF如何删除页面?批量删除不连续页的方法
- dataframe排序 pd.rank()
- 2020少儿编程教育政策大汇总!
- 一套莫尔斯电报听写、翻译系统
- win10 运行debug程序
- 《软件体系结构》习题解答(二)
- HTML5新特性小结
- 论坛,贴吧,Q群,微信个人号群发
- 第一章 管理与管理学 第一节 笔记2018
- 如何参与github开源项目,成为contributor
热门文章
- Struts2 自定义拦截器(easy example)
- QT mainwindow四件套
- c#获取系统时间的方法
- 从MySQL导入导出大量数据的程序实现方法
- android根据拍摄url获取格式,Android如何通过URI获取文件路径示例代码
- 骁龙660是32位还是64位_高通发布骁龙 7c/8c 芯片,以后你可能会在电脑上看到它...
- java21个知识点重点_java21个知识点重点
- java 向父类_Java基础——面向对象(Object父类)
- php 状态码302,HTTP状态码302、303和307的故事
- 索引和未索引执行计划的比较_详解Oracle复合索引+实例说明