zoukankan      html  css  js  c++  java
  • 点分治练习:不虚就是要AK

    【题面】

    不虚就是要AK(czyak.c/.cpp/.pas)

      2s 128M

    czy很火。因为又有人说他虚了。为了证明他不虚,他决定要在这次比赛AK。

    现在他正在和别人玩一个游戏:在一棵树上随机取两个点,如果这两个点的距离是4的倍数,那么算czy赢,否则对方赢。现在czy想知道他能获胜的概率。

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

    本题多组数据。对于每组数据:第一行一个数n,表示树上的节点个数 接下来n-1条边a,b,c描述a到b有一条长度为c的路径 当n=0时表示读入结束

    数据组数不超过10

    输入数据

    5

    1 2 1

    1 3 2

    1 4 1

    2 5 3

    0

    输出数据

    7/25

    数据范围

    数据点 n的规模 数据组数 随机生成数据
    1 200 1
    2 200 1
    3 200 <=3
    4 2000 <=3
    5 2000 <=3
    6 2000 <=5
    7 20000 <=5
    8 20000 <=5
    9 20000 <=10
    10 20000 <=10

    【思路】

           考虑过树根的情况。

           设sum[i]表示前S-1棵子树中dis%4=i的点数,tmp代表当前S子树。

           一遍dfs求出dis后累计答案即可。

           需要注意的是点对算两次而且路长0算作4的倍数。

    【代码】

     1 #include<cstdio>
     2 #include<vector>
     3 #include<queue>
     4 #include<cstring>
     5 #include<iostream>
     6 #include<algorithm>
     7 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
     8 using namespace std;
     9 
    10 const int N = 20000+10;
    11 
    12 struct Edge {
    13     int v,w;
    14     Edge(int v=0,int w=0) :v(v),w(w){}
    15 };
    16 vector<Edge> g[N];
    17 int n,m,k,ans;
    18 int root,size,siz[N],dis[N],f[N],vis[N];
    19 
    20 int gcd(int x,int y) { return y==0? x:gcd(y,x%y); }
    21 
    22 void getroot(int u,int fa) {
    23     siz[u]=1; f[u]=0;
    24     for(int i=0;i<g[u].size();i++) {
    25         int v=g[u][i].v;
    26         if(v!=fa && !vis[v]) {
    27             getroot(v,u);
    28             siz[u]+=siz[v];
    29             if(siz[v]>f[u]) f[u]=siz[v];
    30         }
    31     }
    32     f[u]=max(f[u],size-siz[u]);
    33     if(f[u]<f[root]) root=u;
    34 }
    35 int tmp[4],sum[4];
    36 void dfs(int u,int fa) {
    37     tmp[dis[u]]++;
    38     for(int i=0;i<g[u].size();i++) {
    39         int v=g[u][i].v;
    40         if(v!=fa && !vis[v]) {
    41             dis[v]=(dis[u]+g[u][i].w)%4;
    42             dfs(v,u);
    43         }
    44     }
    45 }
    46 void solve(int u) {
    47     memset(sum,0,sizeof(sum));
    48     vis[u]=1; sum[0]=1;
    49     for(int i=0;i<g[u].size();i++) {
    50         int v=g[u][i].v;
    51         if(!vis[v]) {
    52             dis[v]=g[u][i].w%4;
    53             dfs(v,u);
    54             for(int j=0;j<4;j++)
    55                 ans+=tmp[j]*sum[(4-j)%4];
    56             for(int j=0;j<4;j++)
    57                 sum[j]+=tmp[j],tmp[j]=0;
    58         }
    59     }
    60     for(int i=0;i<g[u].size();i++) {
    61         int v=g[u][i].v;
    62         if(!vis[v]) {
    63             size=siz[v]; root=0;
    64             getroot(v,-1); solve(root);
    65         }
    66     }
    67 }
    68 void read(int& x) {
    69     char c=getchar(); int f=1; x=0;
    70     while(!isdigit(c)){if(c=='-') c=-1; c=getchar();}
    71     while(isdigit(c)) x=x*10+c-'0',c=getchar();
    72     x*=f;
    73 }
    74 int main() {
    75     //freopen("in.in","r",stdin);
    76     //freopen("out.out","w",stdout);
    77     while(read(n),n!=0) {
    78         ans=0;
    79         FOR(i,0,n) g[i].clear();
    80         memset(vis,0,sizeof(vis));
    81         int u,v,w;
    82             FOR(i,1,n-1) {
    83             read(u),read(v),read(w);
    84             g[u].push_back(Edge(v,w));
    85             g[v].push_back(Edge(u,w));
    86         }
    87         root=0; f[0]=1e9; size=n;
    88         getroot(1,-1) , solve(root);
    89         int b=n*n; ans=ans*2+n;
    90         int gc=gcd(ans,b);
    91         printf("%d/%d
    ",ans/gc,b/gc);
    92     }
    93     return 0;
    94 }
  • 相关阅读:
    LeetCode 12. 整数转罗马数字
    [Python] for in range()使用以及列表字符串反转方法
    组合数问题
    「BJOI2020」封印
    数据结构优化建图
    小Q与找茬
    无旋Treap学习
    jzoj5679
    数星星
    凸性
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5189159.html
Copyright © 2011-2022 走看看