codechef Prime Distance On Tree(树分治+FFT)
题目链接: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)的更多相关文章
- 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 ...
- Codechef Prime Distance On Tree
[传送门] FFT第四题! 暑假的时候只会点分,然后合并是暴力合并的...水过去了... 其实两条路径长度的合并就是卷积的过程嘛,每次统计完路径就自卷积一下. 刚开始卷积固定了值域.T了.然后就不偷懒 ...
- prime distance on a tree(点分治+fft)
最裸的点分治+fft,调了好久,太菜了.... #include<iostream> #include<cstring> #include<cstdio> #inc ...
- POJ 1741 Tree 树分治
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...
- POJ 1741.Tree 树分治 树形dp 树上点对
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 24258 Accepted: 8062 Description ...
- poj 1744 tree 树分治
Tree Time Limit: 1000MS Memory Limit: 30000K Description Give a tree with n vertices,each ed ...
- 【BZOJ-1468】Tree 树分治
1468: Tree Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1025 Solved: 534[Submit][Status][Discuss] ...
- HDU 4812 D Tree 树分治+逆元处理
D Tree Problem Description There is a skyscraping tree standing on the playground of Nanjing Unive ...
- HDU4670 Cube number on a tree 树分治
人生的第一道树分治,要是早点学我南京赛就不用那么挫了,树分治的思路其实很简单,就是对子树找到一个重心(Centroid),实现重心分解,然后递归的解决分开后的树的子问题,关键是合并,当要合并跨过重心的 ...
随机推荐
- 防止DC电源反接的方法——SS14的用法
出处:http://blog.ednchina.com/tengjingshu 电源是PCB板的重要部分,每个芯片都需要电源供给.芯片其实是挺脆弱的,只要正负接反得话,大多数就会挂掉,相信很多人都有惨 ...
- 递归转手工栈处理的一般式[C语言]
是任意形式的递归,是化解的一般式. 主题所谓的“递归调用化解为栈处理”,意思是,将递归函数调用化解为“一个由stack_push stack_pop stack_top等函数调用组成的循环式子”.这里 ...
- wikioi1082【线段树练习 3 】
题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述 Input Description 第一行一个正整数n,接下 ...
- 怎样用jQuery自带方法/函数来获取outerHTML属性
原文地址:http://jingyan.baidu.com/article/7f41ececf93b48593d095c25.html 包括我自己在内(其实我也就这两天才知道这样可以快速获取的),很多 ...
- strcat函数的坑点
我们先看下面这样一段代码: #include <iostream> #include <stdlib.h> using namespace std; int main() { ...
- apache2 httpd 基于域名的虚拟主机配置 for centos6X 和debian-8
全系统虚拟主机: for debian 系统的apache2 域名 虚拟主机
- 应用Observer接口实践Observer模式
原文:http://zhangjunhd.blog.51cto.com/113473/68949/ 在Java中通过Observable类和Observer接口实现了观察者模式.Observer对象是 ...
- [原创作品]手把手教你怎么写jQuery插件
这次随笔,向大家介绍如何编写jQuery插件.啰嗦一下,很希望各位IT界的‘攻城狮’们能和大家一起分享,一起成长.点击左边我头像下边的“加入qq群”,一起分享,一起交流,当然,可以一起吹水.哈,不废话 ...
- oracle 使用sql获取数据库表,表的字段
--第一种方法: 查询dba_tab_columns select COLUMN_NAME,DATA_TYPE,DATA_LENGTH from dba_tab_columns where t ...
- UIWindow in iOS
这篇文章,我将分享对UIWindow我所知道的东西. keyWindow 一个应用能够有许多UIWindow,“The key window”是其中一个,被设计用来接受键盘和其他与点击无关的事件.一个 ...