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


    题目:洛谷P2634、BZOJ2152。

    题目大意:有n个点,每个点有一个权值。现在两个人分别选两个点,如果两点的最短路在3进制下个位相等,则规定获胜。求总胜率(获胜选法/所有可能选法),两个人选的不同点调换算两种方案。

    解题思路:点分治,每次找出树的重心,然后以重心为根,递归处理。

    每次统计模3余0 1 2的个数,然后计算答案即可。

    注意要去掉一些走非最短路径的(即重复)。

    时间复杂度$O(nlog_2 n)$。

    C++ Code:

    #include<bits/stdc++.h>
    #define _ __;i
    nt m
    ain(
    ){}
    inline int max(int a,int b){return a>b?a:b;}
    inline int debian(){
        int c=getchar();
        for(;!isdigit(c);c=getchar());
        int d=0;
        for(;isdigit(c);c=getchar())
        d=(d<<3)+(d<<1)+(c^'0');
        return d;
    }
    int __gcd(int a,int b){return b?__gcd(b,a%b):a;}
    static class Main{
        private:
        int n,cnt,head[20005],rt,sz,f[20005],son[20005],ct[3],d[20005],ans;
        bool ur[20005];
        struct edge{
            int to,nxt,dis;
        }e[40005];
        void getdp(int now,int pre){
            ++ct[d[now]];
            for(int i=head[now];i;i=e[i].nxt)
            if(e[i].to!=pre&&!ur[e[i].to]){
                d[e[i].to]=(d[now]+e[i].dis)%3;
                getdp(e[i].to,now);
            }
        }
        int calc(int now,int v){
            ct[0]=ct[1]=ct[2]=0;
            d[now]=v;
            getdp(now,0);
            return ct[0]*ct[0]+((ct[1]*ct[2])<<1);
        }
        void getrt(int now,int pre){
            son[now]=1;
            f[now]=0;
            for(int i=head[now];i;i=e[i].nxt)
            if(!ur[e[i].to]&&e[i].to!=pre){
                getrt(e[i].to,now);
                son[now]+=son[e[i].to];
                f[now]=max(f[now],son[e[i].to]);
            }
            f[now]=max(f[now],sz-son[now]);
            if(f[now]<f[rt])rt=now;
        }
        void dfz(int now){
            ur[now]=true;
            ans+=calc(now,0);
            for(int i=head[now];i;i=e[i].nxt)
            if(!ur[e[i].to]){
                ans-=calc(e[i].to,e[i].dis);
                rt=0;
                sz=son[e[i].to];
                getrt(e[i].to,0);
                dfz(rt);
            }
        }
        public:
        Main():n(debian()),cnt(0),rt(0),ans(0){
            memset(head,0,sizeof head);
            for(int i=1;i<n;++i){
                int x=debian(),y=debian(),z=debian()%3;
                e[++cnt]=(edge){y,head[x],z};
                head[x]=cnt;
                e[++cnt]=(edge){x,head[y],z};
                head[y]=cnt;
            }
            sz=f[0]=n;
            memset(ur,0,sizeof ur);
            getrt(1,0);
            dfz(rt);
            int gcd=__gcd(ans,n*n);
            exit(!printf("%d/%d
    ",ans/gcd,n*n/gcd));
        }
    }_
  • 相关阅读:
    webpack-merge 配置抽离
    从这个博客皮肤迈入前端性能优化一小步
    用 webpack 搭了一个写博客园皮肤的架子
    host 文件位置
    鼠标右键添加取得管理员所有权
    桌面快捷方式去掉小箭头
    win10恢复系统预装软件
    Zookeeper相关知识
    Docker安装常见的应用与将本地镜像推送到阿里云
    DockerFile解析
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8634430.html
Copyright © 2020-2023  润新知