zoukankan      html  css  js  c++  java
  • 洛谷 P2634 [国家集训队]聪聪可可-树分治(点分治,容斥版) +读入挂+手动O2优化吸点氧才过。。。-树上路径为3的倍数的路径数量

    P2634 [国家集训队]聪聪可可

    题目描述

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

    他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画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。

    题意就是找树上任意两点路径为3的倍数的路径数,除以所有路径数。

    点分治,最后两组数据怎么也过不了,今天过了。

    换了个读入挂,也不行,手动吸氧过了。

    不知道为什么老是超时,有点躁。

    关于C++手动开O2优化:

    • O2优化能使程序的编译效率大大提升

    • 从而减少程序的运行时间,达到优化的效果。

    • C++程序中的O2开关如下所示:

    • #pragma GCC optimize(2)
    • 只需将这句话放到程序的开头即可打开O2优化开关。

    一开始手动吸氧也没过,后来可能网络稳了,试了很多次都过了。

    代码:

      1 //点分治
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 #define fin freopen("in.txt", "r", stdin)
      5 #define fout freopen("out.txt", "w", stdout)
      6 #define FI(n) FastIO::read(n)
      7 #pragma GCC optimize(2)//O2优化,手动吸氧才过。。。
      8 typedef long long ll;
      9 const int inf=0x3f3f3f3f;
     10 const int maxn=2e4+10;
     11 const int maxm=1e7+10;
     12 const int mod=3;
     13 
     14 int head[maxn<<1],tot;
     15 int root,allnode,n,m,k;
     16 int vis[maxn],dis[maxn],siz[maxn],maxv[maxn];//maxv为重心节点
     17 int ans[maxn];
     18 ll sum=0;
     19 
     20 //namespace IO{
     21 //    char buf[1<<15],*S,*T;
     22 //    inline char gc(){
     23 //        if (S==T){
     24 //            T=(S=buf)+fread(buf,1,1<<15,stdin);
     25 //            if (S==T)return EOF;
     26 //        }
     27 //        return *S++;
     28 //    }
     29 //    inline int read(){
     30 //        int x; bool f; char c;
     31 //        for(f=0;(c=gc())<'0'||c>'9';f=c=='-');
     32 //        for(x=c^'0';(c=gc())>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^'0'));
     33 //        return f?-x:x;
     34 //    }
     35 //    inline long long readll(){
     36 //        long long x;bool f;char c;
     37 //        for(f=0;(c=gc())<'0'||c>'9';f=c=='-');
     38 //        for(x=c^'0';(c=gc())>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^'0'));
     39 //        return f?-x:x;
     40 //    }
     41 //}
     42 //using IO::read;
     43 //using IO::readll;
     44 
     45 namespace FastIO {//读入挂
     46     const int SIZE = 1 << 16;
     47     char buf[SIZE], obuf[SIZE], str[60];
     48     int bi = SIZE, bn = SIZE, opt;
     49     int read(char *s) {
     50         while (bn) {
     51             for (; bi < bn && buf[bi] <= ' '; bi++);
     52             if (bi < bn) break;
     53             bn = fread(buf, 1, SIZE, stdin);
     54             bi = 0;
     55         }
     56         int sn = 0;
     57         while (bn) {
     58             for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
     59             if (bi < bn) break;
     60             bn = fread(buf, 1, SIZE, stdin);
     61             bi = 0;
     62         }
     63         s[sn] = 0;
     64         return sn;
     65     }
     66     bool read(int& x) {
     67         int n = read(str), bf;
     68 
     69         if (!n) return 0;
     70         int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
     71         for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
     72         if (bf < 0) x = -x;
     73         return 1;
     74     }
     75 };
     76 
     77 ll gcd(ll a,ll b)
     78 {
     79     return b==0?a:gcd(b,a%b);
     80 }
     81 
     82 struct node{
     83     int to,next,val;
     84 }edge[maxn<<1];
     85 
     86 void add(int u,int v,int w)//前向星存图
     87 {
     88     edge[tot].to=v;
     89     edge[tot].next=head[u];
     90     edge[tot].val=w;
     91     head[u]=tot++;
     92 }
     93 
     94 void init()//初始化
     95 {
     96     memset(head,-1,sizeof head);
     97     memset(vis,0,sizeof vis);
     98     tot=0;
     99 }
    100 
    101 void get_root(int u,int father)//求重心
    102 {
    103     siz[u]=1;maxv[u]=0;
    104     for(int i=head[u];~i;i=edge[i].next){
    105         int v=edge[i].to;
    106         if(v==father||vis[v]) continue;
    107         get_root(v,u);
    108         siz[u]+=siz[v];
    109         maxv[u]=max(maxv[u],siz[v]);
    110     }
    111     maxv[u]=max(maxv[u],allnode-siz[u]);//保存节点size
    112     if(maxv[u]<maxv[root]) root=u;//更新保存当前子树的重心
    113 }
    114 
    115 void get_dis(int u,int father)//获取子树所有节点与根的距离
    116 {
    117     ans[dis[u]%mod]++;//保存数量
    118     for(int i=head[u];~i;i=edge[i].next){
    119         int v=edge[i].to;
    120         if(v==father||vis[v]) continue;
    121         int w=edge[i].val;
    122         dis[v]=(dis[u]+w)%mod;
    123         get_dis(v,u);
    124     }
    125 }
    126 
    127 ll cal(int u,int now)//每一棵子树的计算
    128 {
    129     ans[0]=ans[1]=ans[2]=0;
    130     dis[u]=now;
    131     get_dis(u,0);
    132     ll ret=ans[1]*ans[2]*2+ans[0]*(ans[0]-1)+ans[0];//1的加上2的+0的
    133     return ret;
    134 }
    135 
    136 void solve(int u)
    137 {
    138     sum+=cal(u,0);//所有满足的
    139     vis[u]=1;
    140     for(int i=head[u];~i;i=edge[i].next){
    141         int v=edge[i].to;
    142         int w=edge[i].val;
    143         if(vis[v]) continue;
    144         sum-=cal(v,w);//去掉子树的,容斥思想。
    145         allnode=siz[v];
    146         root=0;
    147         get_root(v,u);
    148         solve(root);
    149     }
    150 }
    151 
    152 int main()
    153 {
    154 //    n=read();
    155     FI(n);
    156     init();
    157     for(int i=1;i<n;i++){
    158         int u,v,w;
    159         FI(u),FI(v),FI(w);
    160         add(u,v,w);
    161         add(v,u,w);
    162     }
    163     root=0;allnode=n;maxv[0]=inf;
    164     get_root(1,0);
    165     solve(root);
    166     ll num=n*n;
    167     ll GCD=gcd(sum,num);
    168     printf("%lld/%lld
    ",sum/GCD,num/GCD);
    169 }
  • 相关阅读:
    2020年天梯赛补题报告
    补提报告...
    2020.11.14天梯赛练习*6 补题
    2020-11-08补题报告
    2020-10-30 — 补题报告
    10-24 补题
    2020.10.17天梯赛练习 和 16 号个人赛 补题报告
    elasticsearch DQL 有关表达式的设计
    tab键和空格键
    emacs配置python开发环境
  • 原文地址:https://www.cnblogs.com/ZERO-/p/11649382.html
Copyright © 2011-2022 走看看