zoukankan      html  css  js  c++  java
  • [国家集训队]聪聪可可

    题目:洛谷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));
        }
    }_
  • 相关阅读:
    面向对象第三单元博客作业
    面向对象编程第2次总结(电梯作业)
    面向对象编程第1次总结
    OOP 第四章博客总结
    OO 第三章总结
    OOP 第二章作业总结
    Java 设计模式 -- 代理模式
    ASID 与 MIPS 中 TLB 相关
    Java 锁机制总结
    OOP 第一章作业总结
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8634430.html
Copyright © 2011-2022 走看看