zoukankan      html  css  js  c++  java
  • 题解 CF109C 【Lucky Tree】

    思路:

    (quad)树形(DP +) 容斥 , (f[x]) 表示以 (x) 为根的子树中有几个点到 (x) 的路径包含幸运边, (g[x]) 表示除了 (x) 的子树外有几个点到 (x) 的路径包含幸运边,最后统计答案就是 (ans=sum_{i=1}^n) ((f[i] imes (f[i]-1)+g[i] imes (g[i]-1)+2 imes f[i] imes g[i])),数组 (f)(g) 的转移也很简单,当 (y)(x)的儿子时,若 (x)(y) 的连边为幸运边,那么 (f[x]+=size[y])(y) 的子树(包括 (y))到 (x) 的路径都包含幸运边,否则 (f[x]+=f[y])(g) 的转移也类似,如果x和y的连边是幸运边,那么 (g[y]=(n-size[y])) ,否则 (g[y]=g[x]+f[x]-f[y]) ,两遍 (dfs) 即可完成的操作,一遍自下而上,一遍自上而下,时间复杂度为 (O(3n))

    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define re register int
    #define int long long
    #define LL long long
    #define il inline
    #define next nee
    #define inf 1e18
    il int read()
    {
      int x=0,f=1;char ch=getchar();
      while(!isdigit(ch)&&ch!='-')ch=getchar();
      if(ch=='-')f=-1,ch=getchar();
      while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
      return x*f;
    }
    il void print(int x)
    {
      if(x<0)putchar('-'),x=-x;
      if(x/10)print(x/10);
      putchar(x%10+'0');
    }
    const int N=1e5+5;
    int n,m,next[N<<1],go[N<<1],head[N],tot,father[N],size[N],f[N],g[N],ans;
    bool s[N<<1];
    il bool check(int x)//判断是否是幸运数字
    {
      while(x)
        {
          if(x%10!=7&&x%10!=4)return 0;
          x/=10;
        }
      return 1;
    }
    il void Add(int x,int y,bool z)
    {next[++tot]=head[x];head[x]=tot;go[tot]=y;s[tot]=z;}
    il void dfs1(int x,int fa,bool z)//第一遍dfs,处理f数组
    {
      father[x]=fa;size[x]=1;
      for(re i=head[x],y;i,y=go[i];i=next[i])
        {
          if(y==fa)continue;
          dfs1(y,x,s[i]);
          size[x]+=size[y];
          if(s[i])f[x]+=size[y];
          else f[x]+=f[y];
        }
    }
    il void dfs2(int x)//第二遍dfs,处理g数组
    {
      for(re i=head[x],y;i,y=go[i];i=next[i])
        {
          if(y==father[x])continue;
          if(s[i])g[y]=n-size[y];
          else g[y]=g[x]+f[x]-f[y];
          dfs2(y);
        }
    }
    signed main()
    {
      n=read();
      for(re i=1;i<n;i++)
        {re x=read(),y=read(),z=check(read());Add(x,y,z);Add(y,x,z);}
      dfs1(1,0,0);dfs2(1);
      for(re i=1;i<=n;i++)
        ans+=f[i]*(f[i]-1)+g[i]*(g[i]-1)+f[i]*g[i]*2;//简单的组合数学计算方案
      print(ans);
      return 0;
    }
    
  • 相关阅读:
    URAL 2046 A
    URAL 2056 Scholarship 水题
    Codeforces Gym 100286I iSharp 水题
    Codeforces Gym H. Hell on the Markets 贪心
    Codeforces Gym 100286G Giant Screen 水题
    Codeforces Gym 100286B Blind Walk DFS
    Codeforces Gym 100286F Problem F. Fibonacci System 数位DP
    Codeforces Gym 100286A. Aerodynamics 计算几何 求二维凸包面积
    Codeforces Gym 100418K Cards 暴力打表
    Codeforces Gym 100418J Lucky tickets 数位DP
  • 原文地址:https://www.cnblogs.com/FarkasW/p/14027455.html
Copyright © 2011-2022 走看看