题目链接: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. 使用Qt实现MDI风格的主窗体

    文章来源:http://hi.baidu.com/wuyunju/item/3d20164c99a276f6dc0f6c52 QT提供了MDIArea控件可以很方便的实现标准的MDI窗体,但用起来并不 ...

  2. java decompiler如何去掉行号

    今天想反编译jar包保存源代码,默认前面加了行号,不知道这个小工具如何设置去掉行号? 反编译后: 找到它的安装路径,我的是:C:\Program Files\decomp.然后将该路径加入到环境变量p ...

  3. 基本SQL练习题--选课经典例题

    为管理岗位业务培训信息,建立3个表: S (S#,SN,SD,SA) S#,SN,SD,SA 分别代表学号.学员姓名.所属单位.学员年龄 C (C#,CN ) C#,CN 分别代表课程编号.课程名称 ...

  4. poj3254:基础状压dp

    第二个状压dp 做过的第一个也是放牛问题,两头牛不能相邻 这个题多了一个限制,就是有些位置不能放牛 于是先与处理一下每一行所有不能放牛的状态,处理的过程直接对每一个不能放牛的状态或以下 ac代码: # ...

  5. 【活动】明星衣橱CEO林清华聊创业 | 猎云网

    [活动]明星衣橱CEO林清华聊创业 | 猎云网 [活动]明星衣橱CEO林清华聊创业

  6. poj 1466 Girls and Boys(二分匹配之最大独立集)

    Description In the second year of the university somebody started a study on the romantic relations ...

  7. mysql 从data文件恢复数据库

    安装在D:\mysql\mysql-5.6.24-winx64下的mysql 由于系统坏了,移到另外一台机器上启动 步骤如下 1.复制以前的mysql安装文件及data文件下:2.全新安装mysql3 ...

  8. css中的边框样式

    在盒子模型中,盒子的边框是其重要的样式,通过边框我们可以很方便地看出盒子的长宽以及大小.边框的特性可以通过边框线,边框的宽度及颜色来呈现. 1,边框线 边框线指的是边框线条的样式,包括实线,虚线,点划 ...

  9. 贪心-hdu-1789-Doing Homework again

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1789 题目意思: 有n个作业,每个作业有一个截止日期,每个作业如果超过截止日期完成的时候有一个惩罚值 ...

  10. Perl 多线程模块 Parallel::ForkManager

    Perl 多线程模块 Parallel::ForkManager 一个简单的并行处理模块.这个是用来对付循环的多线程处理. 放在循环前面. Table of Contents 1 Synops内容简介 ...