题目描述

聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。

他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。

聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。

输入输出格式

输入格式:

输入的第1行包含1个正整数n。后面n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,上面的数是w。

输出格式:

以即约分数形式输出这个概率(即“a/b”的形式,其中a和b必须互质。如果概率为1,输出“1/1”)。

输入输出样例

输入样例#1:

5
1 2 1
1 3 2
1 4 1
2 5 3
输出样例#1:

13/25

说明

【样例说明】

13组点对分别是(1,1) (2,2) (2,3) (2,5) (3,2) (3,3) (3,4) (3,5) (4,3) (4,4) (5,2) (5,3) (5,5)。

【数据规模】

对于100%的数据,n<=20000。

题解:
树形DP,f[i][x]表示以i为根的子树,到i的距离%3为x的路径数。

每搜完一个点,就与它的同辈更新一下答案。然后更新一下根节点的f值。

记得最后ans=ans*2+n;因为反过来也是一种答案,并且n个点可以单独成为一个答案,即(n,n)。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
template<typename T>void read(T &x)
{
x=;char c=getchar();
for(;!isdigit(c);c=getchar());
for(;isdigit(c);c=getchar())x=x*+c-'';
}
int head[],size,n,ans;
struct node
{
int next,to,dis;
}edge[];
void putin(int from,int to,int dis)
{
size++;
edge[size].to=to;
edge[size].dis=dis;
edge[size].next=head[from];
head[from]=size;
}
int f[][];
void dfs(int r,int fa)
{
int i;
for(i=head[r];i!=-;i=edge[i].next)
{
int y=edge[i].to;
if(y!=fa)
{
dfs(y,r);
ans+=f[y][-edge[i].dis%]*f[r][]+f[y][(edge[i].dis%<=)?(edge[i].dis%)^:]*f[r][]+f[y][(edge[i].dis%==)?:(edge[i].dis%)^]*f[r][];
f[r][edge[i].dis%]+=f[y][];
f[r][(edge[i].dis+)%]+=f[y][];
f[r][(edge[i].dis+)%]+=f[y][];
}
}
ans+=f[r][];
f[r][]++;
}
int gcd(int a,int b)
{
if(b==)return a;
else return gcd(b,a%b);
}
int main()
{
int i,j;
read(n);
memset(head,-,sizeof(head));
for(i=;i<n;i++)
{
int from,to,dis;
read(from);read(to);read(dis);
putin(from,to,dis);
putin(to,from,dis);
}
dfs(,);
ans=ans*+n;
int k=gcd(ans,n*n);
printf("%d/%d",ans/k,n*n/k);
return ;

点分治代码:

 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m;
struct node{
int next,to,dis;
}edge[];
int head[],size=;
void putin(int from,int to,int dis){
size++;
edge[size].to=to;
edge[size].dis=dis;
edge[size].next=head[from];
head[from]=size;
}
int root,sum,son[],cnt[],vis[];
void getroot(int r,int fa){
int i;
cnt[r]=;
son[r]=;
for(i=head[r];i!=-;i=edge[i].next){
int y=edge[i].to;
if(y!=fa&&!vis[y]){
getroot(y,r);
cnt[r]+=cnt[y];
if(cnt[y]>son[r])son[r]=cnt[y];
}
}
son[r]=max(son[r],sum-cnt[r]);
if(son[r]<son[root])root=r;
}
int ans,dist[],t[];
void getdeep(int r,int fa){
int i;
t[dist[r]]++;
for(i=head[r];i!=-;i=edge[i].next){
int y=edge[i].to;
if(y!=fa&&!vis[y]){
dist[y]=(dist[r]+edge[i].dis)%;
getdeep(y,r);
}
}
}
int getans(int r,int len){
t[]=t[]=t[]=;
dist[r]=len%;
getdeep(r,);
return t[]*t[]*+t[]*t[];
}
void solve(int r){
ans+=getans(r,);
vis[r]=;
for(int i=head[r];i!=-;i=edge[i].next){
int y=edge[i].to;
if(!vis[y]){
ans-=getans(y,edge[i].dis);
root=;
sum=cnt[y];
getroot(y,);
solve(root);
}
}
}
int gcd(int a,int b){
if(b==)return a;
else return gcd(b,a%b);
}
int main(){
int i,j;
memset(head,-,sizeof(head));
scanf("%d",&n);
for(i=;i<n;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
c%=;
putin(a,b,c);
putin(b,a,c);
}
root=;
son[]=sum=n;
getroot(,);
solve(root);
int t=gcd(ans,n*n);
printf("%d/%d\n",ans/t,n*n/t);
return ;
}

[luogu 2634]聪聪可可的更多相关文章

  1. 洛谷 2634&&BZOJ 2152: 聪聪可可【点分治学习+超详细注释】

    2152: 聪聪可可 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 3435  Solved: 1776[Submit][Status][Discuss ...

  2. Luogu 4206 [NOI2005]聪聪与可可

    BZOJ 1415 简单期望 + 记忆化搜索. 发现聪聪每一步走向的地方是在可可的所在位置确定时是确定的,设$nxt_{x, y}$表示聪聪在$x$,可可在$y$时聪聪下一步会走到哪里,我们先预处理出 ...

  3. luogu P2634 [国家集训队]聪聪可可 点分治

    Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...

  4. luogu P4206 [NOI2005]聪聪与可可 期望dp 记忆化搜索

    LINK:聪聪与可可 这道题的核心是 想到如何统计答案. 如果设f[i][j]表示第i个时刻... 可以发现还需要统计位置信息 以及上一次到底被抓到没有的东西 不太好做. 两者的位置都在变化 所以需要 ...

  5. luogu P4206 聪聪和可可

    聪聪和可可 鸽了两天 \(dijkstra\)预处理出来两点之间的最短路径\(dis\)数组,读题发现,\(cat\)的走位很怪sb斩了,所以我们设一个\(next\)数组,\(next[i][j]\ ...

  6. 【P2634】聪聪可可——点分治

    (题面来自Luogu) 题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)--遇到这种问题,一般情况下石头 ...

  7. [bzoj2152][聪聪和可可] (点分治+概率)

    Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...

  8. BZOJ 1415 【NOI2005】 聪聪和可可

    题目链接:聪聪和可可 一道水题--开始还看错题了,以为边带权--强行\(O(n^3)\)预处理-- 首先,我们显然可以预处理出一个数组\(p[u][v]\)表示可可在点\(u\),聪聪在点\(v\)的 ...

  9. 【bzoj1415】 Noi2005—聪聪和可可

    http://www.lydsy.com/JudgeOnline/problem.php?id=1415 (题目链接) 题意 一张图,聪聪想吃可可.每单位时间聪聪可以先移动两次:可可后移动一次或停在原 ...

随机推荐

  1. docker的操作

    查询容器 docker ps  只能查询到正在运行的docker镜像: 如果添加上-a的选项,则会显示所有的(包括已经exit,未启动)的容器 基于一个镜像来构建(run)容器,并启动 docker ...

  2. alter table *** add constraint *** 用法---约束

    1.主键约束:要对一个列加主键约束的话,这列就必须要满足的条件就是分空因为主键约束:就是对一个列进行了约束,约束为(非空.不重复)以下是代码   要对一个列加主键,列名为id,表名为emp 格式为:a ...

  3. POJ1860(ford判环)

    Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 24243   Accepted: 881 ...

  4. shell里的` ` $( ) ${ } expr $(( ))

    转自:http://blog.sina.com.cn/s/blog_6151984a0100ekz2.html 所有UNIX命令,要取结果或输出,都要用$( )或反引号` ` tt=` file te ...

  5. [解决问题]SSH连不上Ubuntu虚拟机解决办法

    1. 安装openssh-client Ubuntu默认缺省安装了openssh-client,apt-get安装即可 sudo apt-get install openssh-client 2. 安 ...

  6. CodeForces 1097G. Vladislav and a Great Legend

    题目简述:给定$n \leq 10^5$个节点的树$T = (V, E)$,令$X \subseteq V$表示一个非空节点集合,定义$f(X)$为包含$X$的最小子树的边数.求 $$ \sum_{\ ...

  7. day5 面向对象

    面向对象的特征 封装(encapsulation) 继承(inheritance) 多态(polymorphism) 开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情. 设计的过程:其实就 ...

  8. 2. nmap扫描神器总结

    -----------------nmap(选项)(参数)------------------O:激活操作探测: -P0:值进行扫描,不ping主机: -PT:是同TCP的ping: -sV:探测服务 ...

  9. 写守护进程时碰到open函数的参数,没记住

    今天写一个最简单的守护进程, 要成为一个守护进程,其实很简单了.主要步骤就4步: 1,创建进程. 2,父进程退出. 3,成为会话的头领进程. 4,将工作目录改成根目录,并把标准输入输出重定向到空设备. ...

  10. 2013年第四届蓝桥杯国赛试题(JavaA组)

    1.结果填空 (满分12分)2.结果填空 (满分15分)3.结果填空 (满分10分)4.程序设计(满分16分)5.程序设计(满分20分)6.程序设计(满分27分) 1.标题:填算式 请看下面的算式: ...