• TYOI Day1 travel:Tree dp【处理重复走边】


    题意:

      给你一棵树,n个节点,每条边有长度。

      然后有q组询问(u,k),每次问你:从节点u出发,走到某个节点的距离mod k的最大值。

    题解:

      对于无根树上的dp,一般都是先转成以1为根的有根树,然后分别从上到下和从下到上两遍dp。

      另一个技巧是:处理重复走边的情况时,可以让dp值表示达到某种状态的方案数。

      表示状态:

        dp[i][j][k] = max dis

        表示从i节点出发,走的距离mod k = j时的方案数

      找出答案:

        对于每次询问(u,k),答案为:满足dp[u][d][k]>0的最大的d值。

      如何转移:

        第一遍dfs:

          dp[i][(j+len)%k][k] = ∑ dp[son][j][k]

          只考虑从上往下的路径。

        第二遍dfs:

          dp[i][(j+len)%k][k] += dp[par][j][k]

          dp[i][(j+len)%k][k] -= old[i][((j-len)%k+k)%k][k]

          其中old[i][j][k]代表原来的dp,即只考虑从上往下时的dp。

          减去old是因为要将会导致重复走边的方案删去。

      边界条件:

        dp[i][0][k] = 1

        others = 0

      复杂度:

        Tree dp: O(n*k*k)

        Query: O(q*k)

    AC Code:

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <vector>
      5 #define MAX_N 3005
      6 #define MAX_K 105
      7 
      8 using namespace std;
      9 
     10 struct Edge
     11 {
     12     int dst;
     13     int len;
     14     Edge(int _dst,int _len)
     15     {
     16         dst=_dst;
     17         len=_len;
     18     }
     19     Edge(){}
     20 };
     21 
     22 int n,q;
     23 int dp[MAX_N][MAX_K][MAX_K];
     24 int old[MAX_N][MAX_K][MAX_K];
     25 vector<Edge> edge[MAX_N];
     26 
     27 void read()
     28 {
     29     cin>>n;
     30     int x,y,z;
     31     for(int i=1;i<n;i++)
     32     {
     33         cin>>x>>y>>z;
     34         edge[x].push_back(Edge(y,z));
     35         edge[y].push_back(Edge(x,z));
     36     }
     37 }
     38 
     39 void dfs1(int now,int p)
     40 {
     41     for(int i=0;i<edge[now].size();i++)
     42     {
     43         Edge temp=edge[now][i];
     44         if(temp.dst!=p) dfs1(temp.dst,now);
     45     }
     46     for(int k=1;k<=100;k++)
     47     {
     48         for(int i=0;i<edge[now].size();i++)
     49         {
     50             Edge temp=edge[now][i];
     51             if(temp.dst!=p)
     52             {
     53                 for(int j=0;j<k;j++)
     54                 {
     55                     dp[now][(j+temp.len)%k][k]+=dp[temp.dst][j][k];
     56                 }
     57             }
     58         }
     59     }
     60 }
     61 
     62 void dfs2(int now,int p,int l)
     63 {
     64     if(p!=-1)
     65     {
     66         for(int k=1;k<=100;k++)
     67         {
     68             for(int j=0;j<k;j++)
     69             {
     70                 old[now][j][k]=dp[now][j][k];
     71             }
     72         }
     73         for(int k=1;k<=100;k++)
     74         {
     75             for(int j=0;j<k;j++)
     76             {
     77                 dp[now][(j+l)%k][k]+=dp[p][j][k];
     78                 dp[now][(j+l)%k][k]-=old[now][((j-l)%k+k)%k][k];
     79             }
     80         }
     81     }
     82     for(int i=0;i<edge[now].size();i++)
     83     {
     84         Edge temp=edge[now][i];
     85         if(temp.dst!=p) dfs2(temp.dst,now,temp.len);
     86     }
     87 }
     88 
     89 void work()
     90 {
     91     memset(dp,0,sizeof(dp));
     92     for(int i=1;i<=n;i++)
     93     {
     94         for(int k=1;k<=100;k++)
     95         {
     96             dp[i][0][k]=1;
     97         }
     98     }
     99     dfs1(1,-1);
    100     dfs2(1,-1,0);
    101     cin>>q;
    102     int u,k;
    103     while(q--)
    104     {
    105         cin>>u>>k;
    106         for(int d=k-1;d>=0;d--)
    107         {
    108             if(dp[u][d][k])
    109             {
    110                 cout<<d<<endl;
    111                 break;
    112             }
    113         }
    114     }
    115 }
    116 
    117 int main()
    118 {
    119     read();
    120     work();
    121 }
  • 相关阅读:
    Git Bash 常用指令
    C/C++连接MySQL数据库执行查询
    question from asktom
    ORACLE AWR报告
    查看oracle表索引
    ORACLE数据库关闭与启动
    SYS vs SYSTEM and SYSDBA vs SYSOPER
    【面试】二叉树遍历的非递归实现
    快速排序的非递归实现
    MySQL数据库基础
  • 原文地址:https://www.cnblogs.com/Leohh/p/8290205.html
Copyright © 2020-2023  润新知