题目描述

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

他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画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. Stop logging "internal dummy connection" in Apache

    Apache 2.x keeps child processes alive by creating internal connections which appear in the log file ...

  2. Qt容器组件(一)之QGroupBox、QScrollArea、QToolBox、QTabWidget

    QT中有九种容器组件,分别是组合框QGroupBox.滚动区QScrollArea.工具箱QToolBox.选项卡QTabWidget.控件栈QWidgetStack.框架QFrame.组件QWidg ...

  3. 自己实现的vector

    #include <iostream> #include <memory> using std::cout; using std::endl; using std::alloc ...

  4. sublime Text3支持vue高亮,sublime Text3格式化Vue

    第一:让sublime Text3支持Vue高亮 PS:我的sublime版本是3126,我不清楚其它版本的是不是这样设置,不过可以看看思路自己摸索下 1.下载可以让vue格式高亮的插件vue-syn ...

  5. ant错误 reference classes not found

    使用ant提示reference classes not found错误 原因是 里面的一些属性的值要用on或者yes或者off或者no..用成其他,例如true,false的话就会有这个提示..

  6. 3-C++程序的结构1.5

    多文件结构和编译预处理命令 1.c++程序的一般组织结构 通常一个项目至少划分为三个文件:类定义文件(*.h文件).类实现文件(*.cpp文件)和类的使用文件(*.cpp,主函数文件).如下: 这三个 ...

  7. 转载TCP-IP协议解释

    本文转载自 http://www.ruanyifeng.com/blog/2009/03/tcp-ip_model.html TCP/IP模型是互联网的基础, 理解 TCP/IP对理解互联网至关重要 ...

  8. 安装Matlab出现Error 1935错误解决方法

    1.开始 - 运行(输入regedit.exe)- 确定或者回车,打开注册表编辑器: 2.在打开的注册表编辑器中找到:HKEY_LOCAL_MACHINE ,并展开:HKEY_LOCAL_MACHIN ...

  9. CF 148D D Bag of mice (概率dp)

    题目链接 D. Bag of mice time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  10. Sharepoint2013搜索学习笔记之创建搜索服务(二)

    第一步,进入管理中心,点击管理服务器上的服务 第二步,在服务器上选择需要承载搜索服务的服务器,并启动服务列表上的sharepoint server search 第三步,从管理中心进入管理服务应用程序 ...