题目链接:http://www.codechef.com/problems/PRIMEDST/

题意:给出一棵树,边长度都是1。每次任意取出两个点(u,v),他们之间的长度为素数的概率为多大?

树分治,对于每个根出发记录边的长度出现几次,然后每次求卷积,用素数表查一下即可添加答案。

 #include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<complex>
#define ll long long
#define N 150005
typedef std::complex<double> cd;
int mark[],p[];
int son[],F[],first[],next[],tot,go[];
int lc,n,sum,dis[],root,vis[],mxdis;
ll a[],b[],c[],A[],B[];
ll ans1=,ans2=;
int read(){
char ch=getchar();int t=,f=;
while (ch<''||ch>''){
if (ch=='-') f=-;
ch=getchar();
}
while (''<=ch&&ch<=''){
t=t*+ch-'';
ch=getchar();
}
return t*f;
}
int bitrev(int t,int n){
int res=;
for (int i=;i<n;i++) res|=((t>>(n-i-))&)<<i;//括号要多加
return res;
}
void fft(cd *a,int n,int rev){
int len=<<n;
static cd y[N];double Pi=acos(-);
for (int i=;i<len;i++) y[i]=a[bitrev(i,n)];
for (int d=;d<len;d<<=){
cd wn(exp(cd(,Pi*rev/d)));
for (int k=;k<len;k+=*d){
cd w(,);
for (int i=k;i<k+d;i++,w*=wn){
cd u=y[i],v=w*y[i+d];
y[i]=u+v;
y[i+d]=u-v;
}
}
}
if (rev==-)
for (int i=;i<len;i++) y[i]/=len;
for (int i=;i<len;i++) a[i]=y[i];
}
void mul(ll *a,int la,ll *b,int lb,ll *c,int &lc){
int len=,n=;
static cd t1[N],t2[N];
for (;len<la*||len<lb*;len<<=,n++);
for (int i=;i<la;i++) t1[i]=cd(a[i],);
for (int i=;i<lb;i++) t2[i]=cd(b[i],);
for (int i=la;i<len;i++) t1[i]=cd(,);
for (int i=lb;i<len;i++) t2[i]=cd(,);
fft(t1,n,);fft(t2,n,);
for (int i=;i<len;i++) t1[i]*=t2[i];
fft(t1,n,-);
for (int i=;i<len;i++) c[i]=(ll)(t1[i].real()+0.5);
lc=len;
}
void insert(int x,int y){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
}
void add(int x,int y){
insert(x,y);
insert(y,x);
}
void prework(){
mark[]=mark[]=;
for (int i=;i<=;i++){
if (!mark[i]){
p[++p[]]=i;
}
for (int j=;j<=p[]&&p[j]*i<=;j++){
mark[p[j]*i]=;
if (i%p[j]==) break;
}
}
}
void findroot(int x,int fa){
son[x]=;
F[x]=;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (vis[pur]||pur==fa) continue;
findroot(pur,x);
son[x]+=son[pur];
F[x]=std::max(F[x],son[pur]);
}
F[x]=std::max(F[x],sum-son[x]);
if (F[x]<F[root]) root=x;
}
void pre(int x,int fa){
dis[x]=dis[fa]+;
mxdis=std::max(mxdis,dis[x]);
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (pur==fa||vis[pur]) continue;
pre(pur,x);
}
}
void dfs(int x,int fa){
b[dis[x]]++;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (pur==fa||vis[pur]) continue;
dis[pur]=dis[x]+;
dfs(pur,x);
}
}
void work(int x){
dis[]=-;mxdis=;
int all=sum;
pre(x,);
for (int i=;i<=mxdis+;i++) a[i]=b[i]=;
a[]=;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (vis[pur]) continue;
dis[pur]=;
for (int j=;j<=mxdis;j++) b[j]=;
dfs(pur,x);
for (int j=;j<=mxdis;j++) A[j]=a[j],B[j]=b[j];
mul(A,mxdis+,B,mxdis+,c,lc);
int lim=std::min(mxdis*,);
for (int i=;i<=p[]&&p[i]<=lim;i++){
ans1+=c[p[i]];
}
for (int i=;i<=mxdis;i++)
a[i]+=b[i];
}
vis[x]=;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (vis[pur]) continue;
if (son[pur]>son[x]) sum=all-son[x];
else sum=son[pur];
root=;
findroot(pur,x);
work(root);
}
}
int main(){
prework();
while (scanf("%d",&n)!=EOF){
if (n==) break;
tot=;
for (int i=;i<=n;i++) first[i]=vis[i]=;
for (int i=;i<n;i++){
int x,y;
x=read();y=read();
add(x,y);
}
root=;sum=n;
F[]=;
ans1=ans2=;
findroot(,);
work(root);
ans2=(ll)(((ll)n)*((ll)(n-))/);
double tmp=((double)(ans1))/((double)(ans2));
printf("%.8lf\n",tmp);
}
}

codechef Prime Distance On Tree(树分治+FFT)的更多相关文章

  1. CodeChef - PRIMEDST Prime Distance On Tree 树分治 + FFT

    Prime Distance On Tree Problem description. You are given a tree. If we select 2 distinct nodes unif ...

  2. Codechef Prime Distance On Tree

    [传送门] FFT第四题! 暑假的时候只会点分,然后合并是暴力合并的...水过去了... 其实两条路径长度的合并就是卷积的过程嘛,每次统计完路径就自卷积一下. 刚开始卷积固定了值域.T了.然后就不偷懒 ...

  3. prime distance on a tree(点分治+fft)

    最裸的点分治+fft,调了好久,太菜了.... #include<iostream> #include<cstring> #include<cstdio> #inc ...

  4. POJ 1741 Tree 树分治

    Tree     Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...

  5. POJ 1741.Tree 树分治 树形dp 树上点对

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 24258   Accepted: 8062 Description ...

  6. poj 1744 tree 树分治

    Tree Time Limit: 1000MS   Memory Limit: 30000K       Description Give a tree with n vertices,each ed ...

  7. 【BZOJ-1468】Tree 树分治

    1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1025  Solved: 534[Submit][Status][Discuss] ...

  8. HDU 4812 D Tree 树分治+逆元处理

    D Tree Problem Description   There is a skyscraping tree standing on the playground of Nanjing Unive ...

  9. HDU4670 Cube number on a tree 树分治

    人生的第一道树分治,要是早点学我南京赛就不用那么挫了,树分治的思路其实很简单,就是对子树找到一个重心(Centroid),实现重心分解,然后递归的解决分开后的树的子问题,关键是合并,当要合并跨过重心的 ...

随机推荐

  1. BZOJ 2527 Meteors

    http://www.lydsy.com/JudgeOnline/problem.php?id=2527 思路:整体二分 #include<cstdio> #include<cmat ...

  2. C#反射 获取程序集信息和通过类名创建类实例(转载)

    C#反射获取程序集信息和通过类名创建类实例 . System.Reflection 命名空间:包含通过检查托管代码中程序集.模块.成员.参数和其他实体的元数据来检索其相关信息的类型. Assembly ...

  3. vim 中Ctags的安装和使用

    Ctags是一个用来为源文件中的标识符(如变量.函数.类成员.宏定义等)创建索引文件的程序.这些tags文件能被编辑器或其它工具用来快速查找定位源代码中的符号(tag/symbol),如变量名,函数名 ...

  4. 关于bootstrap--表单(水平表单)

    在Bootstrap框架中要实现水平表单效果,必须满足以下两个条件:1.在<form>元素是使用类名“form-horizontal”.2.配合Bootstrap框架的网格系统.(网格布局 ...

  5. Struts2简单例子

    Struts实现注册功能 ControlFilter.java package com.jikexueyuan.filter; import java.io.IOException; import j ...

  6. 关于DevExpress的gridControl的简单使用

    数据绑定 首先生成table,然后更改列名,最后添加一个选择列,类型为"System.Boolean",这样在绑定上gridcontrol的时候会出现一列选择框 table.Col ...

  7. C++ multimap 的插入,遍历,删除

    #include <iostream> #include <map> #include <string> using namespace std; int main ...

  8. 自己实现一个SQL解析引擎

    自己实现一个SQL解析引擎 功能:将用户输入的SQL语句序列转换为一个可运行的操作序列,并返回查询的结果集. SQL的解析引擎包含查询编译与查询优化和查询的执行,主要包含3个步骤: 查询分析: 制定逻 ...

  9. C++内存分配的五种方法

    在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区.里面的变量通常是局部变量.函数参数 ...

  10. 【转载】cocos2d-x2.2.3和android的平台环境

    这两天试图按照教程来学习写游戏移植到的横版过关Android在.在网上找了很多教程,但版本号变化.所使用的工具有细微的差别.所以,现在我们还没有准备好,阅读后,下面的文章.最后能够顺利您的手机上跑起来 ...