zoukankan      html  css  js  c++  java
  • 【Luogu】P2634聪聪可可(树形DP)

      题目链接

      水题,时限放得非常宽,暴力DP随便套上一波register就能卡过去。

      唯一的遗憾是5A。

      树形DP,s[i][j]表示以i为根的子树里距i的距离%3=j的点数,f[i]表示i为根的子树内一共有多少满足条件的点对。

      两重循环暴力枚举i的所有儿子,暴力转移加波register即可。

      据说正解是点分治,并不会。回头学学吧(挖坑)。

      

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #include<cstdlib>
    #define maxn 20020
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    struct Edge{
        int next,to,val;
    }edge[maxn*3];
    int head[maxn],num;
    inline void add(int from,int to,int dis){
        edge[++num]=(Edge){head[from],to,dis};
        head[from]=num;
    }
    
    long long s[maxn][3];
    long long f[maxn];
    int sta[maxn],top;
    int dis[maxn];
    
    void build(int x,int fa){
        int lim=top;
        s[x][0]=1;
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(to==fa)    continue;
            sta[++top]=to;
            dis[top]=edge[i].val;
            build(to,x);
            for(int j=0;j<3;++j){
                int ret=(edge[i].val+j)%3;
                s[x][ret]+=s[to][j];
            }
        }
        for(int i=lim+1;i<=top;++i){
            f[x]+=f[sta[i]];
            for(register int j=i+1;j<=top;++j){
                int ret=sta[i],now=sta[j];
                if(ret==now)    continue;
                for(register int k=0;k<3;++k){
                    int opt=(dis[i]+k+dis[j])%3;
                    f[x]+=s[ret][k]*s[now][(3-opt)%3]*2;
                }
            }
        }
        //f[x]*=2;
        f[x]+=s[x][0]+s[x][0]-1;
        top=lim;
    }
    
    inline long long gcd(long long a,long long b){
        return b==0?a:gcd(b,a%b);
    }
    
    int main(){
        int n=read();
        for(int i=1;i<n;++i){
            int from=read(),to=read(),dis=read();
            add(from,to,dis);
            add(to,from,dis);
        }
        build(1,1);
        long long ans=f[1],ret=n*n;
        long long gc=gcd(ans,ret);
        ans/=gc;ret/=gc;
        printf("%lld/%lld",ans,ret);
        return 0;
    }
  • 相关阅读:
    IDE IntelliJ IDEA ToolsTable 窗口找回
    Equals方法与“==”区别
    JAVA虚拟机内存分配与回收机制(转)
    java集合框架总结三--Set接口及其子类
    2014年4月5日 java集合框架总结2--List接口及其子类
    java集合框架总结一
    sql 操作数据库
    EF框架用中使用mysql数据库需要安装mysql-for-visualstudio
    mysql 服务启动不了;无法启动MYSQL服务”1067 进程意外终止”解决办法
    mysql 修改密码
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8377068.html
Copyright © 2011-2022 走看看