zoukankan      html  css  js  c++  java
  • [BZOJ2152]聪聪可可 点分治/树形dp

    2152: 聪聪可可

    Time Limit: 3 Sec  Memory Limit: 259 MB Submit: 3602  Solved: 1858 [Submit][Status][Discuss]

    Description

    聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。

    Input

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

    Output

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

    Sample Input

    5
    1 2 1
    1 3 2
    1 4 1
    2 5 3

    Sample Output

    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,也可以点分治。
    写写点分治……
     
     
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #include<cmath>
     7 using namespace std;
     8 struct data
     9 {
    10     int to,next,c;
    11 }e[40004];
    12 int head[20005];
    13 int cnt=0;
    14 void add(int u,int v,int c){e[cnt].to=v;e[cnt].next=head[u];e[cnt].c=c;head[u]=cnt;cnt++;}
    15 int n;
    16 bool vis[20005];
    17 int f[20005];
    18 int son[20005];
    19 int sum,ans;
    20 int root;
    21 int t[5];
    22 int dis[20005];
    23 void findroot(int now,int fa)
    24 {
    25     son[now]=1;f[now]=0;
    26     for(int i=head[now];i>=0;i=e[i].next)
    27     {
    28         int to=e[i].to;
    29         if(to!=fa&&!vis[to])
    30         {
    31             findroot(to,now);
    32             son[now]+=son[to];
    33             f[now]=max(f[now],son[to]);
    34         }
    35     }
    36     f[now]=max(f[now],sum-son[now]);
    37     if(f[now]<f[root]) root=now;
    38 }
    39 void dfs(int now,int fa)
    40 {
    41     t[dis[now]]++;
    42     for(int i=head[now];i>=0;i=e[i].next)
    43     {
    44         int to=e[i].to;
    45         if(!vis[to]&&to!=fa)
    46         {
    47             dis[to]=(dis[now]+e[i].c)%3;
    48             dfs(to,now);
    49         }
    50     }
    51 }
    52 int cal(int now,int sd)
    53 {
    54     memset(t,0,sizeof(t));
    55     dis[now]=sd%3;dfs(now,0);
    56     return t[1]*t[2]*2+t[0]*t[0];
    57 }
    58 void work(int now)
    59 {
    60     vis[now]=1;
    61     ans+=cal(now,0);
    62     for(int i=head[now];i>=0;i=e[i].next)
    63     {
    64         int to=e[i].to;
    65         if(!vis[to])
    66         {
    67             ans-=cal(to,e[i].c);
    68             root=0;sum=son[to];
    69             findroot(to,0);
    70             work(root);
    71         }
    72     }
    73 }
    74 int gcd(int a,int b)
    75 {
    76     return b==0?a:gcd(b,a%b);
    77 }
    78 int main()
    79 {
    80     memset(head,-1,sizeof(head));
    81     scanf("%d",&n);
    82     for(int i=1;i<n;i++)
    83     {
    84         int u,v,w;
    85         scanf("%d%d%d",&u,&v,&w);
    86         add(u,v,w);
    87         add(v,u,w);
    88     }
    89     f[0]=sum=n;
    90     findroot(1,0);
    91     work(root);
    92     int t=gcd(ans,n*n);
    93     printf("%d/%d",ans/t,n*n/t);
    94 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    C++ 线程的创建、挂起、唤醒和结束 &&&& 利用waitForSingleObject 函数陷入死锁的问题解决
    接收数据界面卡顿-----待整理
    vs2012 在调试或运行的过程中不能加断点
    matlab 学习笔记
    周立功USBCAN-II 上位机开发(MFC)
    vs添加静态链接库+添加动态链接库+添加头文件目录
    Go 面试每天一篇(第 2 天)
    http 协议
    Samba配置
    svn checkout 单个文件
  • 原文地址:https://www.cnblogs.com/wls001/p/7516107.html
Copyright © 2011-2022 走看看