題意:
給你一棵樹,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 }