[luogu 2634]聪聪可可
题目描述
聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。
他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。
聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。
输入输出格式
输入格式:
输入的第1行包含1个正整数n。后面n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,上面的数是w。
输出格式:
以即约分数形式输出这个概率(即“a/b”的形式,其中a和b必须互质。如果概率为1,输出“1/1”)。
输入输出样例
5
1 2 1
1 3 2
1 4 1
2 5 3
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]聪聪可可的更多相关文章
- 洛谷 2634&&BZOJ 2152: 聪聪可可【点分治学习+超详细注释】
2152: 聪聪可可 Time Limit: 3 Sec Memory Limit: 259 MBSubmit: 3435 Solved: 1776[Submit][Status][Discuss ...
- Luogu 4206 [NOI2005]聪聪与可可
BZOJ 1415 简单期望 + 记忆化搜索. 发现聪聪每一步走向的地方是在可可的所在位置确定时是确定的,设$nxt_{x, y}$表示聪聪在$x$,可可在$y$时聪聪下一步会走到哪里,我们先预处理出 ...
- luogu P2634 [国家集训队]聪聪可可 点分治
Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...
- luogu P4206 [NOI2005]聪聪与可可 期望dp 记忆化搜索
LINK:聪聪与可可 这道题的核心是 想到如何统计答案. 如果设f[i][j]表示第i个时刻... 可以发现还需要统计位置信息 以及上一次到底被抓到没有的东西 不太好做. 两者的位置都在变化 所以需要 ...
- luogu P4206 聪聪和可可
聪聪和可可 鸽了两天 \(dijkstra\)预处理出来两点之间的最短路径\(dis\)数组,读题发现,\(cat\)的走位很怪sb斩了,所以我们设一个\(next\)数组,\(next[i][j]\ ...
- 【P2634】聪聪可可——点分治
(题面来自Luogu) 题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)--遇到这种问题,一般情况下石头 ...
- [bzoj2152][聪聪和可可] (点分治+概率)
Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...
- BZOJ 1415 【NOI2005】 聪聪和可可
题目链接:聪聪和可可 一道水题--开始还看错题了,以为边带权--强行\(O(n^3)\)预处理-- 首先,我们显然可以预处理出一个数组\(p[u][v]\)表示可可在点\(u\),聪聪在点\(v\)的 ...
- 【bzoj1415】 Noi2005—聪聪和可可
http://www.lydsy.com/JudgeOnline/problem.php?id=1415 (题目链接) 题意 一张图,聪聪想吃可可.每单位时间聪聪可以先移动两次:可可后移动一次或停在原 ...
随机推荐
- ntp服务器同步时间详细配置
部署NTP服务器进行时间同步 NTP服务端:linl_S IP:10.0.0.15 NTP客户端:lin_C IP:10.0.0.16 NTP服务概述 1.原理 NTP(Network ...
- zynq基础
zynq交叉编译环境设置 OpenCV在Zedboard上的移植 ubuntu 下串口调试工具 minicom安装与配置
- 好文章!转载嵌入式LINUX
整理了嵌入式linux学习路线供参考,希望对您有所参考价值! 一.linux入门 目前嵌入式主要开发环境有 Linux.Wince等:Linux因其开源.开发操作便利而被广泛采用.而Linux操作系统 ...
- 三 lambda表达式有什么用
(转载: https://mp.weixin.qq.com/s/-PHOc6p-qKJBktle28AUgA) 一: 直接把代码块赋值给变量 我们知道,对于一个Java变量,我们可以赋给其一个“值”. ...
- François Hollande’s&…
EVER since President François Hollande was elected last May, things have not gone right for him. He ...
- 2. DVWA亲测文件包含漏洞
Low级: 我们分别点击这几个file.php文件 仅仅是配置参数的变化: http://127.0.0.1/DVWA/vulnerabilities/fi/?page=file3.php 如 ...
- HDU 5546 Ancient Go (搜索)
题意: Alice和Bob正在下古代围棋,规则如下: 棋盘有8×8个格子,棋子下在棋盘的交叉点上,故可以有9×9个落子的位置 Alice执黑棋Bob执白棋轮流落子 与棋子直线相连的空白交叉点叫做气.当 ...
- POJ - 3268 Silver Cow Party SPFA+SLF优化 单源起点终点最短路
Silver Cow Party One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbered 1..N is going to ...
- iscsi使用教程
服务端 服务器环境 已经安装过qemu-img的32位ubuntu $ uname -a Linux ubuntu-virtual-machine 3.13.0-46-generic #76-Ubun ...
- SCUT - 205 - 饲养牛 - 最大流
https://scut.online/p/205 连着做所以一开始就觉得是网络流. 这种至多分配几次的很有网络流的特征. 一开始想从食物和饮料流向牛,但是怎么搞都不对. 其实可以从s流向食物,食物流 ...