zoukankan      html  css  js  c++  java
  • bzoj2152【树形dp】聪聪和可可

    这道题还是比较显然的,我们用dp[x][y]来表示在x这个点往下取一条路段和sum%3==y的路有几种方案,很明显它可以
    由dp[son[x]][(y+3-w)%3]来更新(w为son[x]到x这段路的长度)

    ,如果用ans[x]来表示以x为根的子树中有多少种方案,我们分两种情况,第一种这段路不经过x点那么很明显,它肯定已被
    计算在ans[son[x]]中,所以我们要把ans[x]加上ans[son[x]]

    ,第二种,经过x点,那么这段路就由不同x的不同儿子上的两条链连接起来,假设当前子树的一个儿子上,有a条路段和(sum%3)==2的,
    那么a*dp[x][1]就是连接起来为0的一部分答案,

    但是因为dp[x][1]中有一部分链也是在这个儿子上的,所以加上的不是a*dp[x][1],事实上还要去掉在同一个儿子路径的答案。
    不过查了一下,这其实是点分治的裸题,不过我不会啊!!
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<vector>
    #define maxn 20009
    using namespace std;
    vector<int>g1[maxn],g2[maxn];
    bool vis[maxn];
    vector< pair<int,int> >son[maxn];
    int dp[maxn][5],n,ans[maxn];
    int getgcd(int x,int y)
    {
      if (y==0)     return x;
      return getgcd(y,x%y);
    } 
    void dfs(int x)
    {
      if (vis[x]) return;
      vis[x]=true;
      dp[x][0]=1;
    //因为可以直接去在本身,所以要赋初值为1
      for (int i=0;i<g1[x].size();i++)
      if (!vis[g1[x][i]])
      {
          int to=g1[x][i],w=g2[x][i];
          w=w%3;
          son[x].push_back(make_pair(to,w));
          dfs(to);
          ans[x]+=ans[to];
          for (int j=0;j<=2;j++) dp[x][(j+w)%3]+=dp[to][j];
      }
      ans[x]+=dp[x][0];
    //因为方案如果同取在一个点就算一个答案,所以要加上。
      int t1,t2;
    //下面是计算经过X点两条链构成的方案
      for (int i=0;i<son[x].size();i++)
      {
        pair<int,int>to=son[x][i];
          for (int j=0;j<=2;j++)
          {
            t1=(3-(j+to.second)%3)%3;
            t2=(t1+3-to.second)%3;
            ans[x]+=dp[to.first][j]*(dp[x][t1]-dp[to.first][t2]); 
            //cout<<x<<" "<<son[i].first<<" "<<t1<<" "<<t2<<endl;
        }
      }
    }
    int main()
    {
      scanf("%d",&n);
      int x,y,w;
      for (int i=1;i<n;i++)
      {
          scanf("%d%d%d",&x,&y,&w);
          g1[x].push_back(y);g2[x].push_back(w);
          g1[y].push_back(x);g2[y].push_back(w);
      }
      dfs(1);
      int ans1=ans[1],ans2=n*n; 
      int gcd=getgcd(ans2,ans1);
      printf("%d/%d",ans1/gcd,ans2/gcd);
      return 0;
    } 
     
  • 相关阅读:
    301 重定向(iis,Apache,asp,php,ColdFusion,旧域名),永久重定向实现方法。
    转静态页的几种可行方案
    查看域名是否被搜索引擎惩罚(被K被封)过的几种方法
    网站优化工具推荐大全
    html Ajax读取数据
    ADO 读取Excel文件数据, 丢失数据或数据错误问题。
    百度K站解封之道(真实案例)
    舌苔发白是什么原因造成的?
    小技巧—设置IIS禁止网站放下载电影文件
    SQL Server利用数据库日志恢复数据到时间点的操作
  • 原文地址:https://www.cnblogs.com/2014nhc/p/7978872.html
Copyright © 2011-2022 走看看