题目链接: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. Struts2配置RESULT中TYPE的参数说明

    chain           用来处理Action链,被跳转的action中仍能获取上个页面的值,如request信息.           com.opensymphony.xwork2.Acti ...

  2. 2014.7.8模拟赛【笨笨当粉刷匠】|bzoj1296 [SCOI]粉刷匠

    笨笨太好玩了,农田荒芜了,彩奖用光了,笨笨只好到处找工作,笨笨找到了一份粉刷匠的工作.笨笨有n条木板需要被粉刷.每条木板被分成m个格子,每个格子要被刷成红色或蓝色.笨笨每次粉刷,只能选择一条木板上一段 ...

  3. Android:TextView跑马灯-详解

    Android:TextView跑马灯_详解 引言: TextView之所以需要跑马灯,是由于文字太长,或者是吸引眼球. 关键代码如下: android:singleLine="true&q ...

  4. [HEOI 2013 day2] SAO (树形动态规划)

    题目大意 给一棵N个节点的有向树(N <= 1000),求其拓扑序列个数. 思路 我们将任意一个点作为根,用dp[i][j]表示以节点i为根的子树满足节点i在第j个位置上的拓扑序列的个数.在求节 ...

  5. ext3中xtype属性汇总

    基本组件: xtype Class 描述 button Ext.Button 按钮 splitbutton Ext.SplitButton 带下拉菜单的按钮 cycle Ext.CycleButton ...

  6. Entity framework - start

    http://blogs.msdn.com/b/adonet/archive/2010/07/19/absolue-beginners-guide-to-entity-framework.aspx?R ...

  7. 自己意淫的一个简陋的Python网站扫描器

    使用的模块 threading.optparse.urllib2 本地需要放字典,名字需大写. 上代码 def request(url,pathName): try: import urllib2 p ...

  8. Vagrant入门[转]

    Vagrant是一个简单易用的部署工具,用英文说应该是orchestration tool.它能帮助开发人员迅速的构建一个开发环境,帮助测试人员构建测试环境. Vagrant的基本工作原理大致如下: ...

  9. 正确的安装qwtplot3D开发库

    1.从网上下载qwtplot3D的最新版本:http://qwtplot3d.sourceforge.net/ 2.解压qwtplot3d-0.2.7.zip到C盘根目录下(注意:路径中不能带有中文汉 ...

  10. Android调用系统邮件类应用的正确实现方法

    Android应用开发中,很多情况下免不了要调用手机上的邮件类应用,实现邮件发送的功能,这一般是通过调用系统已有的Intent来实现的.看到网上很多邮件发送都是调用action为android.con ...