暑假集训刷题记录
向上跳,再向上跳,也许再努力一点我就能够着菊苣们的膝盖了。
——题记
7.23
CodeForces 559C 组合数 + DP
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <map> 5 #define MP make_pair 6 #define F first 7 #define S second 8 using namespace std; 9 10 typedef long long LL; 11 typedef pair<LL, LL> Point; 12 13 const int maxn = 22000 + 10; 14 const LL MOD = 1000000007LL; 15 16 inline LL mul_mod(LL a, LL b) 17 { 18 a %= MOD; b %= MOD; 19 return (a * b) % MOD; 20 } 21 22 inline LL sub_mod(LL a, LL b) 23 { 24 return (((a - b) % MOD) + MOD) % MOD; 25 } 26 27 LL pow_mod(LL a, LL n) 28 { 29 LL ans = 1; 30 while(n) 31 { 32 if(n & 1) ans = mul_mod(ans, a); 33 a = mul_mod(a, a); 34 n >>= 1; 35 } 36 return ans; 37 } 38 39 LL Inverse(LL a) 40 { return pow_mod(a, MOD - 2); } 41 42 const int maxh = 200000 + 10; 43 44 LL fac[maxh], invfac[maxh]; 45 46 void init() 47 { 48 fac[0] = fac[1] = 1; 49 for(int i = 2; i < maxh; i++) fac[i] = mul_mod(fac[i-1], i); 50 invfac[maxh-1] = Inverse(fac[maxh-1]); 51 for(int i = maxh-2; i >= 0; i--) invfac[i] = mul_mod(invfac[i+1], i+1); 52 } 53 54 LL C(LL n, LL m) 55 { 56 if(m > n) { puts("shakalaka"); return 0; } 57 return mul_mod(mul_mod(fac[n], invfac[m]), invfac[n-m]); 58 } 59 60 int h, w, n; 61 62 Point a[maxn]; 63 64 LL methods(int i, int j) 65 { 66 LL x = a[j].first - a[i].first; 67 LL y = a[j].second - a[i].second; 68 return C(x + y, x); 69 } 70 71 LL dp[maxn]; 72 73 int main() 74 { 75 //freopen("in.txt", "r", stdin); 76 77 init(); 78 scanf("%d%d%d", &h, &w, &n); 79 for(int i = 1; i <= n; i++) 80 { 81 LL x, y; scanf("%I64d%I64d", &x, &y); 82 a[i] = MP(x, y); 83 } 84 sort(a + 1, a + n + 1); 85 a[0] = MP(1, 1); 86 a[n+1] = MP(h, w); 87 dp[1] = methods(0, 1); 88 89 for(int i = 2; i <= n + 1; i++) 90 { 91 dp[i] = methods(0, i); 92 for(int j = 1; j < i; j++) if(a[j].F <= a[i].F && a[j].S <= a[i].S) 93 dp[i] = sub_mod(dp[i], mul_mod(methods(j, i), dp[j])); 94 } 95 96 printf("%I64d\n", dp[n + 1]); 97 98 return 0; 99 }
CodeForces 219D 树形DP
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 7 const int maxn = 200000 + 10; 8 int n; 9 10 vector<int> G[maxn]; 11 vector<bool> f[maxn]; 12 13 int L[maxn]; 14 int fa[maxn]; 15 int up[maxn]; 16 int rev[maxn]; 17 int totup; 18 19 void dfs(int u, int father, int d) 20 { 21 L[u] = d; 22 fa[u] = father; 23 for(int i = 0; i < G[u].size(); i++) 24 { 25 int v = G[u][i]; 26 if(v == father) continue; 27 if(!f[u][i]) { totup++; up[v] = up[u] + 1; } 28 else up[v] = up[u]; 29 dfs(v, u, d + 1); 30 } 31 } 32 33 int main() 34 { 35 //freopen("in.txt", "r", stdin); 36 scanf("%d", &n); 37 for(int i = 0; i < n-1; i++) 38 { 39 int u, v; scanf("%d%d", &u, &v); 40 G[u].push_back(v); f[u].push_back(true); 41 G[v].push_back(u); f[v].push_back(false); 42 } 43 44 dfs(1, 0, 0); 45 46 for(int v = 1; v <= n; v++) 47 rev[v] = totup - up[v] + L[v] - up[v]; 48 49 int ans = n - 1; 50 for(int i = 1; i <= n; i++) ans = min(ans, rev[i]); 51 52 printf("%d\n", ans); 53 54 vector<int> hehe; 55 for(int i = 1; i <= n; i++) if(rev[i] == ans) hehe.push_back(i); 56 57 printf("%d", hehe[0]); 58 for(int i = 1; i < hehe.size(); i++) printf(" %d", hehe[i]); 59 puts(""); 60 61 return 0; 62 }
7.24 补多校
7.25
CodeForces 445B Tire树上的博弈
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 5 const int maxn = 100000 + 10; 6 const int sigma_size = 26; 7 8 int sz; 9 int ch[maxn][sigma_size]; 10 char str[maxn]; 11 12 void insert(char* s) 13 { 14 int u = 0; 15 for(int i = 0; s[i]; i++) 16 { 17 int c = s[i] - 'a'; 18 if(!ch[u][c]) ch[u][c] = sz++; 19 u = ch[u][c]; 20 } 21 } 22 23 bool win[maxn], lose[maxn]; 24 25 void dfs(int u) 26 { 27 bool isleaf = true; 28 for(int c = 0; c < 26; c++) if(ch[u][c]) 29 { 30 isleaf = false; 31 int v = ch[u][c]; 32 dfs(v); 33 win[u] |= !win[v]; 34 lose[u] |= !lose[v]; 35 } 36 if(isleaf) win[u] = false, lose[u] = true; 37 } 38 39 int main() 40 { 41 int n, k; scanf("%d%d", &n, &k); 42 43 sz = 1; 44 for(int i = 0; i < n; i++) 45 { 46 scanf("%s", str); 47 insert(str); 48 } 49 dfs(0); 50 51 if(!win[0]) puts("Second"); 52 else if(lose[0]) puts("First"); 53 else if(k & 1) puts("First"); 54 else puts("Second"); 55 56 return 0; 57 }
HDU 3996 网络流 最大权闭合图
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 #include <queue> 6 using namespace std; 7 8 typedef long long LL; 9 10 const int maxn = 3000; 11 const LL INF = 10000000000; 12 13 struct Edge 14 { 15 int from, to; 16 LL cap, flow; 17 Edge(int u, int v, LL c, LL f):from(u), to(v), cap(c), flow(f) {} 18 }; 19 20 struct Dinic 21 { 22 int n, m, s, t; 23 vector<Edge> edges; 24 vector<int> G[maxn]; 25 int d[maxn], cur[maxn]; 26 bool vis[maxn]; 27 28 void init() { for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); } 29 30 void AddEdge(int u, int v, LL c) 31 { 32 edges.push_back(Edge(u, v, c, 0)); 33 edges.push_back(Edge(v, u, 0, 0)); 34 m = edges.size(); 35 G[u].push_back(m - 2); 36 G[v].push_back(m - 1); 37 } 38 39 bool BFS() 40 { 41 memset(vis, false, sizeof(vis)); 42 queue<int> Q; 43 Q.push(s); 44 vis[s] = true; 45 d[s] = 0; 46 47 while(!Q.empty()) 48 { 49 int u = Q.front(); Q.pop(); 50 for(int i = 0; i < G[u].size(); i++) 51 { 52 Edge& e = edges[G[u][i]]; 53 int v = e.to; 54 if(!vis[v] && e.cap > e.flow) 55 { 56 vis[v] = true; 57 d[v] = d[u] + 1; 58 Q.push(v); 59 } 60 } 61 } 62 63 return vis[t]; 64 } 65 66 LL DFS(int u, LL a) 67 { 68 if(u == t || a == 0) return a; 69 LL flow = 0, f; 70 for(int& i = cur[u]; i < G[u].size(); i++) 71 { 72 Edge& e = edges[G[u][i]]; 73 int v = e.to; 74 if(d[v] == d[u] + 1 && (f = DFS(v, min(a, e.cap-e.flow))) > 0) 75 { 76 flow += f; 77 e.flow += f; 78 a -= f; 79 edges[G[u][i]^1].flow -= f; 80 if(a == 0) break; 81 } 82 } 83 return flow; 84 } 85 86 LL MaxFlow() 87 { 88 LL flow = 0; 89 while(BFS()) 90 { 91 memset(cur, 0, sizeof(cur)); 92 flow += DFS(s, INF); 93 } 94 return flow; 95 } 96 }g; 97 98 int main() 99 { 100 int T; scanf("%d", &T); 101 for(int kase = 1; kase <= T; kase++) 102 { 103 int n; scanf("%d", &n); 104 g.n = n * 25 + 2; 105 g.init(); 106 g.s = 0; g.t = g.n - 1; 107 108 LL sum = 0; 109 for(int i = 0; i < n; i++) 110 { 111 int num; scanf("%d", &num); 112 for(int j = 1; j <= num; j++) 113 { 114 int x = i * 25 + j; 115 LL cost, value; 116 int rela; 117 scanf("%I64d%I64d%d", &cost, &value, &rela); 118 119 value -= cost; 120 if(value > 0) { g.AddEdge(0, x, value); sum += value; } 121 else g.AddEdge(x, g.t, -value); 122 123 while(rela--) 124 { 125 int a, b; scanf("%d%d", &a, &b); a--; 126 int y = a * 25 + b; 127 g.AddEdge(x, y, INF); 128 } 129 } 130 } 131 132 printf("Case #%d: %I64d\n", kase, sum - g.MaxFlow()); 133 } 134 135 return 0; 136 }
HDU 3472 网络流 混合图的欧拉路径
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 using namespace std; 8 9 const int maxn = 30; 10 const int INF = 1000000000; 11 12 struct Edge 13 { 14 int from, to, cap, flow; 15 Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f) {} 16 }; 17 18 struct Dinic 19 { 20 int n, m, s, t; 21 vector<Edge> edges; 22 vector<int> G[maxn]; 23 int d[maxn], cur[maxn]; 24 bool vis[maxn]; 25 26 void init() { m = 0; for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); } 27 28 void AddEdge(int u, int v, int c) 29 { 30 edges.push_back(Edge(u, v, c, 0)); 31 edges.push_back(Edge(v, u, 0, 0)); 32 m = edges.size(); 33 G[u].push_back(m - 2); 34 G[v].push_back(m - 1); 35 } 36 37 bool BFS() 38 { 39 memset(vis, false, sizeof(vis)); 40 queue<int> Q; 41 Q.push(s); 42 d[s] = 0; 43 vis[s] = true; 44 45 while(!Q.empty()) 46 { 47 int u = Q.front(); Q.pop(); 48 for(int i = 0; i < G[u].size(); i++) 49 { 50 Edge& e = edges[G[u][i]]; 51 int v = e.to; 52 if(!vis[v] && e.cap > e.flow) 53 { 54 vis[v] = true; 55 d[v] = d[u] + 1; 56 Q.push(v); 57 } 58 } 59 } 60 61 return vis[t]; 62 } 63 64 int DFS(int u, int a) 65 { 66 if(u == t || a == 0) return a; 67 int flow = 0, f; 68 for(int& i = cur[u]; i < G[u].size(); i++) 69 { 70 Edge& e = edges[G[u][i]]; 71 int v = e.to; 72 if(d[v] == d[u] + 1 && (f = DFS(v, min(a, e.cap-e.flow))) > 0) 73 { 74 flow += f; 75 e.flow += f; 76 a -= f; 77 edges[G[u][i]^1].flow -= f; 78 if(a == 0) break; 79 } 80 } 81 return flow; 82 } 83 84 int MaxFlow() 85 { 86 int flow = 0; 87 while(BFS()) 88 { 89 memset(cur, 0, sizeof(cur)); 90 flow += DFS(s, INF); 91 } 92 return flow; 93 } 94 }g; 95 96 const int maxm = 1000 + 10; 97 int n; 98 char word[30]; 99 100 int deg[maxn]; 101 102 bool occur[maxn]; 103 104 int pa[maxn]; 105 int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); } 106 void Union(int x, int y) 107 { 108 int px = findset(x), py = findset(y); 109 if(px != py) pa[px] = py; 110 } 111 112 int u[maxm], v[maxm], directed[maxm]; 113 int id[maxm]; 114 115 int main() 116 { 117 //freopen("in.txt", "r", stdin); 118 119 int T; scanf("%d", &T); 120 for(int kase = 1; kase <= T; kase++) 121 { 122 printf("Case %d: ", kase); 123 124 g.n = 28; 125 g.s = 26, g.t = 27; 126 g.init(); 127 int n; scanf("%d", &n); 128 129 for(int i = 0; i < 26; i++) pa[i] = i; 130 memset(id, 0, sizeof(id)); 131 memset(occur, false, sizeof(occur)); 132 memset(deg, 0, sizeof(deg)); 133 memset(directed, 0, sizeof(directed)); 134 for(int i = 0; i < n; i++) 135 { 136 scanf("%s%d", word, directed + i); 137 int l = strlen(word); 138 u[i] = word[0] - 'a'; 139 v[i] = word[l - 1] - 'a'; 140 occur[u[i]] = occur[v[i]] = true; 141 Union(u[i], v[i]); 142 deg[u[i]]++; deg[v[i]]--; 143 if(directed[i]) 144 { 145 id[i] = g.m; 146 g.AddEdge(u[i], v[i], 1); 147 } 148 } 149 150 //Judge the graph is connected 151 int root; 152 bool ok = true; 153 for(int i = 0; i < 26; i++) if(occur[i]) { root = findset(i); break; } 154 for(int i = 0; i < 26; i++) if(occur[i] && findset(i) != root) { ok = false; break; } 155 int cnt = 0; 156 for(int i = 0; i < 26; i++) if(deg[i] & 1) cnt++; 157 if((cnt != 0) && cnt != 2) ok = false; 158 if(!ok) { puts("Poor boy!"); continue; } 159 160 for(int i = 0; i < 26; i++) if(deg[i]) 161 { 162 if(deg[i] > 0) g.AddEdge(g.s, i, deg[i] / 2); 163 else if(deg[i] < 0) g.AddEdge(i, g.t, -deg[i] / 2); 164 } 165 g.MaxFlow(); 166 167 for(int i = 0; i < n; i++) if(directed[i]) 168 { 169 int x = id[i]; 170 if(g.edges[x].flow == 1) 171 { deg[u[i]] -= 2; deg[v[i]] += 2; } 172 } 173 174 int a1 = 0, a2 = 0; 175 for(int i = 0; i < 26; i++) if(deg[i]) 176 { 177 if(deg[i] == 1) a1++; 178 else if(deg[i] == -1) a2++; 179 } 180 if((a1 == 0 && a2 == 0) || (a1 == 1 || a2 == 1)) puts("Well done!"); 181 else puts("Poor boy!"); 182 } 183 184 return 0; 185 }
HDU 4183 网络流 每个点只能走一次的回路
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 using namespace std; 9 10 const int maxn = 1000; 11 const int INF = 1000000000; 12 int n; 13 14 struct Edge 15 { 16 int from, to, cap, flow; 17 Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f) {} 18 }; 19 20 struct Dinic 21 { 22 int n, m, s, t; 23 vector<Edge> edges; 24 vector<int> G[maxn]; 25 int d[maxn], cur[maxn]; 26 bool vis[maxn]; 27 28 void init() { m = 0; edges.clear(); for(int i = 0; i < n; i++) G[i].clear(); } 29 30 void AddEdge(int u, int v, int c) 31 { 32 edges.push_back(Edge(u, v, c, 0)); 33 edges.push_back(Edge(v, u, 0, 0)); 34 m = edges.size(); 35 G[u].push_back(m - 2); 36 G[v].push_back(m - 1); 37 } 38 39 bool BFS() 40 { 41 memset(vis, false, sizeof(vis)); 42 queue<int> Q; 43 Q.push(s); 44 vis[s] = true; 45 d[s] = 0; 46 47 while(!Q.empty()) 48 { 49 int u = Q.front(); Q.pop(); 50 for(int i = 0; i < G[u].size(); i++) 51 { 52 Edge& e = edges[G[u][i]]; 53 int v = e.to; 54 if(!vis[v] && e.cap > e.flow) 55 { 56 vis[v] = true; 57 d[v] = d[u] + 1; 58 Q.push(v); 59 } 60 } 61 } 62 63 return vis[t]; 64 } 65 66 int DFS(int u, int a) 67 { 68 if(u == t || a == 0) return a; 69 int flow = 0, f; 70 for(int& i = cur[u]; i < G[u].size(); i++) 71 { 72 Edge& e = edges[G[u][i]]; 73 int v = e.to; 74 if(d[v] == d[u] + 1 && (f = DFS(v, min(a, e.cap-e.flow))) > 0) 75 { 76 flow += f; 77 e.flow += f; 78 a -= f; 79 edges[G[u][i]^1].flow -= f; 80 if(a == 0) break; 81 } 82 } 83 return flow; 84 } 85 86 int MaxFlow() 87 { 88 int flow = 0; 89 while(BFS()) 90 { 91 memset(cur, 0, sizeof(cur)); 92 flow += DFS(s, INF); 93 } 94 return flow; 95 } 96 }g; 97 98 const double eps = 1e-6; 99 100 int dcmp(double x) 101 { 102 if(fabs(x) < eps) return 0; 103 return x < 0 ? -1 : 1; 104 } 105 106 struct Pad 107 { 108 double freq, x, y, r; 109 bool operator < (const Pad& rhs) const 110 { return freq > rhs.freq; } 111 }a[maxn]; 112 113 bool Intersect(int i, int j) 114 { 115 double d = sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x) + (a[i].y-a[j].y)*(a[i].y-a[j].y)); 116 return dcmp(a[i].r + a[j].r - d) > 0; 117 } 118 119 int main() 120 { 121 //freopen("in.txt", "r", stdin); 122 123 int T; scanf("%d", &T); 124 while(T--) 125 { 126 scanf("%d", &n); 127 g.n = n * 2 - 1; 128 g.init(); 129 g.s = 0, g.t = n-1; 130 for(int i = 0; i < n; i++) 131 { 132 scanf("%lf%lf%lf%lf", &a[i].freq, &a[i].x, &a[i].y, &a[i].r); 133 } 134 sort(a, a + n); 135 136 if(Intersect(0, n-1)) { puts("Game is VALID"); continue; } 137 138 g.AddEdge(0, n, 2); 139 for(int i = 1; i < n - 1; i++) g.AddEdge(i, i + n, 1); 140 for(int i = 0; i < n; i++) 141 for(int j = i + 1; j < n; j++) 142 if(dcmp(a[i].freq - a[j].freq) > 0 && Intersect(i, j)) 143 g.AddEdge(i + n, j, INF); 144 145 if(g.MaxFlow() == 2) puts("Game is VALID"); 146 else puts("Game is NOT VALID"); 147 } 148 149 return 0; 150 }
CodeForces 461B 树形DP 跪舔题解
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <vector> 5 using namespace std; 6 7 typedef long long LL; 8 9 const int maxn = 100000 + 100; 10 const LL MOD = 1000000000 + 7; 11 int n; 12 int color[maxn]; 13 vector<int> G[maxn]; 14 15 LL dp[maxn][2]; 16 17 void dfs(int u, int fa) 18 { 19 dp[u][color[u]] = 1; 20 for(int i = 0; i < G[u].size(); i++) 21 { 22 int v = G[u][i]; 23 if(v == fa) continue; 24 dfs(v, u); 25 dp[u][1] = ((dp[u][1] * (dp[v][0] + dp[v][1])) % MOD + (dp[u][0]*dp[v][1])%MOD)%MOD; 26 dp[u][0] = (dp[u][0] * ((dp[v][0] + dp[v][1])%MOD))%MOD; 27 } 28 } 29 30 int main() 31 { 32 scanf("%d", &n); 33 for(int u = 1; u < n; u++) 34 { 35 int v; scanf("%d", &v); 36 G[u].push_back(v); 37 G[v].push_back(u); 38 } 39 for(int i = 0; i < n; i++) scanf("%d", color + i); 40 dfs(0, -1); 41 printf("%I64d", dp[0][1]); 42 43 return 0; 44 }
7.26
CodeForces 455C 给出一个森林,可以合并两棵树。合并以后得到的新树的最小直径为。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 7 const int maxn = 300000 + 10; 8 int n, m, Q; 9 10 int diameter[maxn]; 11 12 bool vis[maxn]; 13 int pa[maxn]; 14 int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); } 15 void Union(int x, int y) 16 { 17 int px = findset(x), py = findset(y); 18 if(px != py) pa[px] = py; 19 } 20 21 vector<int> G[maxn]; 22 23 int len, id; 24 25 void dfs(int u, int fa, int d) 26 { 27 if(d > len) { len = d; id = u; } 28 for(int i = 0; i < G[u].size(); i++) 29 { 30 int v = G[u][i]; 31 if(v != fa) dfs(v, u, d + 1); 32 } 33 } 34 35 int longest(int v) 36 { 37 len = -1; 38 dfs(v, -1, 0); 39 len = -1; 40 dfs(id, -1, 0); 41 return len; 42 } 43 44 int main() 45 { 46 scanf("%d%d%d", &n, &m, &Q); 47 48 for(int i = 1; i <= n; i++) pa[i] = i; 49 while(m--) 50 { 51 int u, v; scanf("%d%d", &u, &v); 52 G[u].push_back(v); 53 G[v].push_back(u); 54 Union(u, v); 55 } 56 57 for(int i = 1; i <= n; i++) 58 { 59 int p = findset(i); 60 if(!vis[p]) 61 { 62 vis[p] = true; 63 diameter[p] = longest(p); 64 } 65 } 66 67 while(Q--) 68 { 69 int op, x, y; 70 scanf("%d%d", &op, &x); 71 if(op == 1) 72 { 73 printf("%d\n", diameter[findset(x)]); 74 } 75 else 76 { 77 scanf("%d", &y); 78 int px = findset(x), py = findset(y); 79 if(px == py) continue; 80 pa[px] = py; 81 int t = (diameter[px] + 1) / 2 + (diameter[py] + 1) / 2 + 1; 82 diameter[py] = max(diameter[px], max(diameter[py], t)); 83 } 84 } 85 86 return 0; 87 }
CodeForces 274B 树形DP
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 8 typedef long long LL; 9 10 const int maxn = 100000 + 10; 11 12 int n; 13 14 vector<int> G[maxn]; 15 LL val[maxn]; 16 LL add[maxn], sub[maxn]; 17 18 void dfs(int u, int fa) 19 { 20 for(int i = 0; i < G[u].size(); i++) 21 { 22 int v = G[u][i]; 23 if(v != fa) 24 { 25 dfs(v, u); 26 add[u] = max(add[u], add[v]); 27 sub[u] = max(sub[u], sub[v]); 28 } 29 } 30 val[u] += add[u] - sub[u]; 31 if(val[u] > 0) sub[u] += val[u]; 32 else if(val[u] < 0) add[u] += -val[u]; 33 } 34 35 int main() 36 { 37 scanf("%d", &n); 38 for(int i = 1; i < n; i++) 39 { 40 int u, v; scanf("%d%d", &u, &v); 41 G[u].push_back(v); 42 G[v].push_back(u); 43 } 44 for(int i = 1; i <= n; i++) scanf("%I64d", val + i); 45 46 dfs(1, -1); 47 printf("%I64d\n", add[1] + sub[1]); 48 49 return 0; 50 }
CodeForces 337D
题意:给出一棵n个节点的树,和m个特定的点。求这棵树中距所有这m个点的距离不超过d的点的个数。
题解本来是给的DP的做法,评论下面有个给出了一种更好的方法:用类似求树的直径办法求出这m个点中相距最远的两个点a、b,然后算出所有点到a、b的距离。最终答案所统计的点就是距a、b不超过d的点的个数。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 100000 + 10; 9 10 vector<int> G[maxn]; 11 12 int n, m, d; 13 14 int p[maxn]; 15 bool mark[maxn]; 16 17 int a, b; 18 19 int len, id; 20 21 void dfs1(int u, int fa, int d) 22 { 23 if(mark[u] && d > len) { len = d; id = u; } 24 for(int i = 0; i < G[u].size(); i++) 25 { 26 int v = G[u][i]; 27 if(v == fa) continue; 28 dfs1(v, u, d + 1); 29 } 30 } 31 32 int La[maxn], Lb[maxn]; 33 34 void dfs2(int u, int fa, int d, int* L) 35 { 36 L[u] = d; 37 for(int i = 0; i < G[u].size(); i++) 38 { 39 int v = G[u][i]; 40 if(v == fa) continue; 41 dfs2(v, u, d + 1, L); 42 } 43 } 44 45 int main() 46 { 47 //freopen("in.txt", "r", stdin); 48 49 scanf("%d%d%d", &n, &m, &d); 50 for(int i = 0; i < m; i++) 51 { 52 scanf("%d", p + i); 53 mark[p[i]] = true; 54 } 55 for(int i = 1; i < n; i++) 56 { 57 int u, v; scanf("%d%d", &u, &v); 58 G[u].push_back(v); G[v].push_back(u); 59 } 60 61 len = -1; 62 dfs1(p[0], 0, 0); 63 a = id; 64 len = -1; 65 dfs1(a, 0, 0); 66 b = id; 67 68 dfs2(a, 0, 0, La); 69 dfs2(b, 0, 0, Lb); 70 71 int ans = 0; 72 for(int i = 1; i <= n; i++) if(La[i] <= d && Lb[i] <= d) ans++; 73 printf("%d\n", ans); 74 75 return 0; 76 }
CodeForces 486D 树形DP 枚举集合中值最小的点(如果点一样的话就枚举取编号最小的那个)
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 using namespace std; 7 8 typedef long long LL; 9 10 const int maxn = 2000 + 10; 11 const LL MOD = 1000000007; 12 13 int d, n, root; 14 int a[maxn]; 15 vector<int> G[maxn]; 16 17 LL dfs(int u, int fa) 18 { 19 LL ans = 1; 20 for(int i = 0; i < G[u].size(); i++) 21 { 22 int v = G[u][i]; 23 if(v == fa) continue; 24 if(a[v] < a[root] || a[v] > a[root] + d) continue; 25 if(a[v] == a[root] && v < root) continue; 26 ans = (ans * (dfs(v, u) + 1)) % MOD; 27 } 28 return ans; 29 } 30 31 int main() 32 { 33 scanf("%d%d", &d, &n); 34 for(int i = 1; i <= n; i++) scanf("%d", a + i); 35 for(int i = 1; i < n; i++) 36 { 37 int u, v; scanf("%d%d", &u, &v); 38 G[u].push_back(v); G[v].push_back(u); 39 } 40 41 LL ans = 0; 42 for(int i = 1; i <= n; i++) 43 { 44 root = i; 45 ans = (ans + dfs(i, 0)) % MOD; 46 } 47 48 printf("%I64d\n", ans); 49 50 return 0; 51 }
POJ 3744 概率DP + 矩阵快速幂优化
先不考虑地雷,设f(x)表示走到位置x的概率。则有递推关系。所以在一段没有地雷的区间,可以快速计算走x步的概率。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 typedef double Mat[2][2]; 8 9 const int maxn = 12; 10 int n; 11 double p; 12 int pos[maxn]; 13 14 Mat A, E; 15 16 void mul(Mat A, Mat B, Mat ans) 17 { 18 Mat C; 19 memset(C, 0, sizeof(C)); 20 for(int i = 0; i < 2; i++) 21 for(int j = 0; j < 2; j++) 22 for(int k = 0; k < 2; k++) 23 C[i][j] += A[i][k] * B[k][j]; 24 memcpy(ans, C, sizeof(C)); 25 } 26 27 void pow(Mat A, int n, Mat ans) 28 { 29 Mat a, r; 30 memcpy(a, A, sizeof(a)); 31 memset(r, 0, sizeof(r)); 32 r[0][0] = r[1][1] = 1; 33 while(n) 34 { 35 if(n & 1) mul(r, a, r); 36 mul(a, a, a); 37 n >>= 1; 38 } 39 40 memcpy(ans, r, sizeof(r)); 41 } 42 43 int main() 44 { 45 //freopen("in.txt", "r", stdin); 46 47 while(scanf("%d", &n) == 1 && n) 48 { 49 scanf("%lf", &p); 50 for(int i = 0; i < n; i++) scanf("%d", pos + i); 51 sort(pos, pos + n); 52 n = unique(pos, pos + n) - pos; 53 54 if(pos[0] == 1) { puts("0.0000000"); continue; } 55 bool flag = false; 56 for(int i = 0; i + 1 < n; i++) if(pos[i] + 1 == pos[i+1]) { flag = true; break; } 57 if(flag) { puts("0.0000000"); continue; } 58 59 Mat x, t; 60 x[0][0] = 0; x[0][1] = 1; x[1][0] = 1- p; x[1][1] = p; 61 pow(x, pos[0] - 2, t); 62 double ans = t[1][1]; 63 64 for(int i = 1; i < n; i++) 65 { 66 ans *= 1.0 - p; 67 pow(x, pos[i]-pos[i-1]-2, t); 68 ans *= t[1][1]; 69 } 70 71 printf("%.7f\n", ans * (1.0 - p)); 72 } 73 74 return 0; 75 }
7.27
POJ 2096 Collecting Bugs 概率DP
d(i, j)表示已经发现i种BUG且属于j个子系统,距离目标的期望天数。然后逆推
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 const int maxn = 1000 + 10; 7 8 double d[maxn][maxn]; 9 10 int n, s; 11 12 int main() 13 { 14 while(scanf("%d%d", &n, &s) == 2) 15 { 16 d[n][s] = 0; 17 double ns = n * 1.0 * s; 18 for(int i = n; i >= 0; i--) 19 for(int j = s; j >= 0; j--) 20 { 21 if(i == n && j == s) continue; 22 double p1 = (double)(i*j)/ns; 23 double p2 = (double)((n-i)*j)/ns; 24 double p3 = (double)(i*(s-j))/ns; 25 double p4 = (double)(n-i)*(s-j)/ns; 26 d[i][j] = (p2*d[i+1][j] + p3*d[i][j+1] + p4*d[i+1][j+1] + 1.0) / (1.0 - p1); 27 } 28 29 printf("%.4f\n", d[0][0]); 30 } 31 32 return 0; 33 }
CodeForces 148D Bag of mice 概率DP
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 const int maxn = 1000 + 10; 7 8 int w, b; 9 10 bool vis[maxn][maxn]; 11 12 double d[maxn][maxn]; 13 14 double DP(int w, int b) 15 { 16 if(w <= 0) return 0; 17 if(b <= 0) return 1; 18 if(vis[w][b]) return d[w][b]; 19 vis[w][b] = true; 20 21 double& ans = d[w][b]; 22 ans = w * 1.0 / (w + b); 23 24 double t = b * 1.0 / ( w + b); 25 b--; 26 t *= b * 1.0 / ( w + b); 27 b--; 28 29 if(t > 1e-13) 30 { 31 double ta = (w * 1.0 / (w + b)) * DP(w-1, b); 32 double tb = (b * 1.0 / (w + b)) * DP(w, b-1); 33 ans += t * (ta + tb); 34 } 35 36 return ans; 37 } 38 39 int main() 40 { 41 scanf("%d%d", &w, &b); 42 printf("%.9f\n", DP(w, b)); 43 44 return 0; 45 }
ZOJ 3329 One Person Game 概率DP
这是个有换的概率DP,需要神奇地将式子变形一下。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int n; 7 int k1, k2, k3; 8 int a, b, c; 9 10 const int maxn = 500 + 20; 11 12 double A[maxn], B[maxn]; 13 14 double pro[20]; 15 16 int main() 17 { 18 int T; scanf("%d", &T); 19 while(T--) 20 { 21 scanf("%d%d%d%d%d%d%d", &n, &k1, &k2, &k3, &a, &b, &c); 22 int tot = k1 + k2 + k3; 23 24 memset(pro, 0, sizeof(pro)); 25 double t = 1.0 / (1.0 * k1 * k2 * k3); 26 for(int i = 1; i <= k1; i++) 27 for(int j = 1; j <= k2; j++) 28 for(int k = 1; k <= k3; k++) 29 if(i != a || j != b || k != c) 30 pro[i+j+k] += t; 31 32 memset(A, 0, sizeof(A)); 33 memset(B, 0, sizeof(B)); 34 for(int i = n; i >= 0; i--) 35 { 36 A[i] = t; B[i] = 1.0; 37 for(int j = 3; j <= tot; j++) 38 { 39 A[i] += pro[j] * A[i + j]; 40 B[i] += pro[j] * B[i + j]; 41 } 42 } 43 44 printf("%.15f\n", B[0] / (1.0 - A[0])); 45 } 46 47 return 0; 48 }
HDU 4405 Aeroplane chess 概率DP
一维的概率DP直接递推就行了,设d(i)表示在第i个格子,还需走的次数的期望。如果x能直接走到y,则d(x) = d(y)。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int n, m; 7 8 const int maxn = 100000 + 10; 9 const int maxm = 1000 + 10; 10 const double p0 = 1.0 / 6.0; 11 int p[maxn]; 12 double d[maxn]; 13 14 int main() 15 { 16 while(scanf("%d%d", &n, &m) == 2 && n) 17 { 18 memset(p, 0, sizeof(p)); 19 while(m--) 20 { 21 int x, y; scanf("%d%d", &x, &y); 22 p[x] = y; 23 } 24 memset(d, 0, sizeof(d)); 25 26 for(int i = n-1; i >= 0; i--) 27 { 28 if(p[i]) d[i] = d[p[i]]; 29 else 30 { 31 d[i] = 1; 32 for(int j = 1; j <= 6; j++) 33 d[i] += p0 * d[i + j]; 34 } 35 } 36 37 printf("%.4f\n", d[0]); 38 } 39 40 return 0; 41 }
HDU 4089 && UVa 1498 Activation 带环的概率DP
7.28
HDU 4035 Maze 树上的概率DP
这题好难,简直要把人难哭了。题解戳这
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 10000 + 10; 9 const double eps = 1e-10; 10 11 int n; 12 double A[maxn], B[maxn], C[maxn]; 13 double e[maxn], k[maxn]; 14 15 vector<int> G[maxn]; 16 17 bool dfs(int u, int fa) 18 { 19 int m = G[u].size(); 20 21 if(m == 1 && fa) 22 { 23 A[u] = k[u]; 24 B[u] = C[u] = 1.0 - k[u] - e[u]; 25 return true; 26 } 27 28 double sigA = 0, sigB = 0, sigC = 0; 29 for(int i = 0; i < G[u].size(); i++) 30 { 31 int v = G[u][i]; 32 if(v == fa) continue; 33 if(!dfs(v, u)) return false; 34 sigA += A[v]; 35 sigB += B[v]; 36 sigC += C[v]; 37 } 38 39 double tt = (1 - k[u] - e[u]) / m; 40 double t = 1.0 - tt * sigB; 41 if(fabs(t) < eps) return false; 42 43 A[u] = (k[u] + tt * sigA) / t; 44 B[u] = tt / t; 45 C[u] = (tt * sigC + 1.0 - k[u] - e[u]) / t; 46 47 return true; 48 } 49 50 int main() 51 { 52 //freopen("in.txt", "r", stdin); 53 54 int T; scanf("%d", &T); 55 for(int kase = 1; kase <= T; kase++) 56 { 57 printf("Case %d: ", kase); 58 59 scanf("%d", &n); 60 for(int i = 1; i <= n; i++) G[i].clear(); 61 for(int i = 1; i < n; i++) 62 { 63 int u, v; scanf("%d%d", &u, &v); 64 G[u].push_back(v); G[v].push_back(u); 65 } 66 67 for(int i = 1; i <= n; i++) 68 { 69 scanf("%lf%lf", k + i, e + i); 70 k[i] /= 100.0; e[i] /= 100.0; 71 } 72 73 if(!dfs(1, 0) || fabs(A[1] - 1.0) < eps) puts("impossible"); 74 else printf("%.6f\n", C[1] / (1.0 - A[1])); 75 } 76 77 return 0; 78 }
HDU 3853 概率DP
递推方程式很容易就写出来了。但是有一个坑点就是,当某个格子的P1 = 1时,妹子就会困死在原地,根据方程式来看答案不就变成无穷大了吗,而题目中说了最终答案小于1e6。AC的做法应该是直接把这种情况的期望变为0,=_-||
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6 7 const int maxn = 1000 + 10; 8 9 const double eps = 1e-8; 10 11 int n, m; 12 13 double p[maxn][maxn][3]; 14 double E[maxn][maxn]; 15 16 int main() 17 { 18 while(scanf("%d%d", &n, &m) == 2 && n) 19 { 20 for(int i = 1; i <= n; i++) 21 for(int j = 1; j <= m; j++) 22 for(int k = 0; k < 3; k++) scanf("%lf", &p[i][j][k]); 23 memset(E, 0, sizeof(E)); 24 25 for(int i = n; i >= 1; i--) 26 for(int j = m; j >= 1; j--) 27 { 28 if(i == n && j == m) continue; 29 if(fabs(1.0 - p[i][j][0]) < eps) continue; 30 double t = 1.0 - p[i][j][0]; 31 double p2 = p[i][j][1], p3 = p[i][j][2]; 32 E[i][j] = p2 / t * E[i][j+1] + p3 / t * E[i+1][j] + 2.0 / t; 33 } 34 35 printf("%.3f\n", E[1][1]); 36 } 37 38 return 0; 39 }
7.29
补多校题目。
POJ 2151 概率DP
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 int n, m, cham; 8 9 const int maxn = 35; 10 const int maxm = 1000 + 10; 11 12 double p[maxm][maxn]; 13 double d[maxm][maxn][maxn]; 14 15 int main() 16 { 17 while(scanf("%d%d%d", &m, &n, &cham) == 3) 18 { 19 if(n == 0 && m == 0 && cham == 0) break; 20 for(int i = 1; i <= n; i++) 21 for(int j = 1; j <= m; j++) scanf("%lf", &p[i][j]); 22 23 for(int i = 1; i <= n; i++) { d[i][1][1] = p[i][1]; d[i][1][0] = 1.0 - p[i][1]; } 24 25 for(int i = 1; i <= n; i++) 26 for(int j = 2; j <= m; j++) 27 for(int k = 0; k <= j; k++) 28 { 29 if(k == 0) d[i][j][k] = d[i][j-1][k] * (1.0 - p[i][j]); 30 else d[i][j][k] = p[i][j]*d[i][j-1][k-1] + (1.0-p[i][j])*d[i][j-1][k]; 31 } 32 33 double ans1 = 1, ans2 = 1; 34 for(int i = 1; i <= n; i++) 35 { 36 double p1 = 0, p2 = 0; 37 for(int j = 1; j <= m; j++) 38 { 39 p1 += d[i][m][j]; 40 if(j < cham) p2 += d[i][m][j]; 41 } 42 ans1 *= p1; 43 ans2 *= p2; 44 } 45 46 printf("%.3f\n", ans1 - ans2); 47 } 48 49 return 0; 50 }
POJ 3071 概率DP 又到了神奇的位运算出场的时候了
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 double p[150][150]; 8 double d[10][150]; 9 10 int main() 11 { 12 //freopen("in.txt", "r", stdin); 13 14 int n; 15 while(scanf("%d", &n) == 1 && n + 1) 16 { 17 for(int i = 0; i < (1<<n); i++) 18 for(int j = 0; j < (1<<n); j++) scanf("%lf", &p[i][j]); 19 memset(d, 0, sizeof(d)); 20 for(int i = 0; i < (1 << n); i++) d[0][i] = 1.0; 21 for(int i = 1; i <= n; i++) 22 for(int j = 0; j < (1 << n); j++) 23 for(int k = 0; k < (1 << n); k++) 24 if(((k >> (i-1)) ^ 1) == (j >> (i-1))) 25 d[i][j] += d[i-1][j] * d[i-1][k] * p[j][k]; 26 27 double M = 0.0; 28 int id; 29 for(int i = 0; i < (1 << n); i++) if(d[n][i] > M) { M = d[n][i]; id = i; } 30 printf("%d\n", id + 1); 31 } 32 33 return 0; 34 }
7.30
ZOJ 3380 概率DP 看了网上好多题解,「感觉」有点不靠谱。因为既然把状态定义为
dp[i][j]表示当前已经放了j个位置,用到了第i种颜色
既然用到了第i种颜色,那为什么代码中k还是从0开始循环呢?
我觉得从0开始循环应该表示考虑过第i种颜色,可以出现可以不出现。所以不符合要求的方案应该就是d[n][m],而不是sum{d[1~n][m]}
但是为什么他们能AC我就想不通了,智商余额不足。。
1 import java.util.*; 2 import java.io.*; 3 import java.math.*; 4 5 public class Main 6 { 7 static BigInteger[][] dp = new BigInteger[110][110]; 8 static BigInteger[][] C = new BigInteger[110][110]; 9 10 public static void main(String arg[]) 11 { 12 Scanner cin = new Scanner(new BufferedInputStream(System.in)); 13 for(int i = 0; i < 105; i++) 14 { 15 C[i][0] = C[i][i] = BigInteger.ONE; 16 for(int j = 1; j < i; j++) 17 C[i][j] = C[i-1][j].add(C[i-1][j-1]); 18 } 19 20 int n, m, l; 21 while(cin.hasNext()) 22 { 23 m = cin.nextInt(); 24 n = cin.nextInt(); 25 l = cin.nextInt(); 26 BigInteger tot = BigInteger.valueOf(n).pow(m); 27 28 if(l > m) 29 { 30 System.out.println("mukyu~"); 31 continue; 32 } 33 34 if(l > m / 2) 35 { 36 BigInteger ans = BigInteger.ZERO; 37 for(int i = l; i <= m; i++) 38 ans = ans.add(C[m][i].multiply(BigInteger.valueOf(n-1).pow(m-i))); 39 ans = ans.multiply(BigInteger.valueOf(n)); 40 BigInteger g = ans.gcd(tot); 41 System.out.println(ans.divide(g) + "/" + tot.divide(g)); 42 continue; 43 } 44 45 for(int i = 0; i <= n; i++) 46 for(int j = 0; j <= m; j++) dp[i][j] = BigInteger.ZERO; 47 dp[0][0] = BigInteger.ONE; 48 49 for(int i = 1; i <= n; i++) 50 for(int j = 0; j <= m; j++) 51 for(int k = 0; k <= j && k < l; k++) 52 dp[i][j] = dp[i][j].add(dp[i-1][j-k].multiply(C[j][k])); 53 BigInteger ans = tot.subtract(dp[n][m]); 54 BigInteger g = ans.gcd(tot); 55 System.out.println(ans.divide(g) + "/" + tot.divide(g)); 56 } 57 } 58 }
ZOJ 3640 概率DP
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 20000 + 10; 9 const double hehe = (1.0 + sqrt(5)) / 2.0; 10 int n, f; 11 double d[maxn]; 12 int t[maxn]; 13 int c[maxn]; 14 15 double E(int f) 16 { 17 if(d[f]) return d[f]; 18 d[f] = 0; 19 for(int i = 0; i < n; i++) 20 { 21 if(f > c[i]) d[f] += t[i]; 22 else d[f] += E(f + c[i]) + 1; 23 } 24 d[f] /= n; 25 return d[f]; 26 } 27 28 int main() 29 { 30 while(scanf("%d%d", &n, &f) == 2) 31 { 32 for(int i = 0; i < n; i++) 33 { 34 scanf("%d", c + i); 35 t[i] = hehe * c[i] * c[i]; 36 } 37 38 memset(d, 0, sizeof(d)); 39 printf("%.3f\n", E(f)); 40 } 41 42 return 0; 43 }
HDU 1054 树形DP
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 2000; 9 int d[2][maxn]; 10 int n; 11 vector<int> G[maxn]; 12 13 void dfs(int u, int fa) 14 { 15 d[0][u] = 0; 16 d[1][u] = 1; 17 for(int i = 0; i < G[u].size(); i++) 18 { 19 int v = G[u][i]; 20 if(v == fa) continue; 21 dfs(v, u); 22 d[0][u] += d[1][v]; 23 d[1][u] += min(d[0][v], d[1][v]); 24 } 25 } 26 27 int main() 28 { 29 while(scanf("%d", &n) == 1 && n) 30 { 31 for(int i = 0; i < n; i++) G[i].clear(); 32 for(int i = 0; i < n; i++) 33 { 34 int u, t, v; 35 scanf("%d:(%d)", &u, &t); 36 for(int j = 0; j < t; j++) 37 { 38 scanf("%d", &v); 39 G[u].push_back(v); 40 G[v].push_back(u); 41 } 42 } 43 dfs(0, -1); 44 printf("%d\n", min(d[0][0], d[1][0])); 45 } 46 47 return 0; 48 }
HDU 2376 树形DP
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 10000 + 10; 9 10 int n; 11 int fa[maxn], d[maxn]; 12 int u[maxn], v[maxn], w[maxn]; 13 vector<int> G[maxn]; 14 15 void dfs(int u, int father) 16 { 17 d[u] = 1; 18 fa[u] = father; 19 for(int i = 0; i < G[u].size(); i++) 20 { 21 int v = G[u][i]; 22 if(v == father) continue; 23 dfs(v, u); 24 d[u] += d[v]; 25 } 26 } 27 28 int main() 29 { 30 int T; scanf("%d", &T); 31 while(T--) 32 { 33 scanf("%d", &n); 34 for(int i = 0; i < n; i++) G[i].clear(); 35 for(int i = 1; i < n; i++) 36 { 37 scanf("%d%d%d", u + i, v + i, w + i); 38 G[u[i]].push_back(v[i]); 39 G[v[i]].push_back(u[i]); 40 } 41 42 dfs(0, 0); 43 44 double sum = 0; 45 for(int i = 1; i < n; i++) 46 { 47 int x = u[i], y = v[i]; 48 if(fa[x] == y) swap(x, y); 49 int ta = d[y], tb = n - d[y]; 50 sum += (double)ta * tb * w[i]; 51 } 52 double mu = n * 1.0 * (n-1) / 2; 53 printf("%.9f\n", sum / mu); 54 } 55 56 return 0; 57 }
POJ 1986 LCA模板题 开始几发WA原来是因为数组开小了
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 100000 + 10; 9 10 vector<int> G[maxn], c[maxn]; 11 12 int n, m; 13 14 int dis[maxn]; 15 int fa[maxn]; 16 int L[maxn]; 17 int anc[maxn][15]; 18 19 void dfs(int u, int father, int d) 20 { 21 fa[u] = father; 22 L[u] = d; 23 for(int i = 0; i < G[u].size(); i++) 24 { 25 int v = G[u][i]; 26 if(v == father) continue; 27 dis[v] = dis[u] + c[u][i]; 28 dfs(v, u, d + 1); 29 } 30 } 31 32 int LCA(int p, int q) 33 { 34 if(L[p] < L[q]) swap(p, q); 35 int log; 36 for(log = 1; (1 << log) <= L[p]; log++); log--; 37 for(int i = log; i >= 0; i--) 38 if(L[p] - (1 << i) >= L[q]) p = anc[p][i]; 39 if(p == q) return q; 40 for(int i = log; i >= 0; i--) 41 if(anc[p][i] && anc[p][i] != anc[q][i]) 42 p = anc[p][i], q = anc[q][i]; 43 return fa[p]; 44 } 45 46 int main() 47 { 48 //freopen("in.txt", "r", stdin); 49 50 scanf("%d%d", &n, &m); 51 for(int i = 0; i < m; i++) 52 { 53 int u, v, d; 54 scanf("%d%d%d", &u, &v, &d); 55 G[u].push_back(v); c[u].push_back(d); 56 G[v].push_back(u); c[v].push_back(d); 57 getchar(); getchar(); 58 } 59 60 dfs(1, 0, 0); 61 62 for(int i = 1; i <= n; i++) 63 { 64 anc[i][0] = fa[i]; 65 for(int j = 1; (1 << j) < n; j++) anc[i][j] = 0; 66 } 67 68 for(int j = 1; (1 << j) < n; j++) 69 for(int i = 1; i <= n; i++) if(anc[i][j-1]) 70 anc[i][j] = anc[anc[i][j-1]][j-1]; 71 72 int Q; scanf("%d", &Q); 73 while(Q--) 74 { 75 int u, v; 76 scanf("%d%d", &u, &v); 77 int lca = LCA(u, v); 78 printf("%d\n", dis[u] + dis[v] - dis[lca] * 2); 79 } 80 81 return 0; 82 }
POJ 1655 树形DP
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 20000 + 10; 9 10 int n; 11 int d[maxn], b[maxn]; 12 13 vector<int> G[maxn]; 14 15 void dfs(int u, int fa) 16 { 17 d[u] = 1; 18 b[u] = 0; 19 for(int i = 0; i < G[u].size(); i++) 20 { 21 int v = G[u][i]; 22 if(v == fa) continue; 23 dfs(v, u); 24 d[u] += d[v]; 25 b[u] = max(b[u], d[v]); 26 } 27 b[u] = max(b[u], n - d[u]); 28 } 29 30 int main() 31 { 32 int T; scanf("%d", &T); 33 while(T--) 34 { 35 scanf("%d", &n); 36 for(int i = 1; i <= n; i++) G[i].clear(); 37 for(int i = 1; i < n; i++) 38 { 39 int u, v; scanf("%d%d", &u, &v); 40 G[u].push_back(v); 41 G[v].push_back(u); 42 } 43 44 dfs(1, 0); 45 46 int ans = b[1], id = 1; 47 for(int i = 2; i <= n; i++) 48 if(b[i] < ans || (b[i] == ans && i < id)) { ans = b[i]; id = i; } 49 50 printf("%d %d\n", id, ans); 51 } 52 53 return 0; 54 }
POJ 1935 树形DP 5W个点要开10W的数组,Why?
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 100000 + 10; 7 8 struct Edge 9 { 10 int v, w, nxt; 11 }edges[maxn]; 12 int sz; 13 int head[maxn]; 14 bool vis[maxn]; 15 int dis[maxn]; 16 int n, m, root; 17 18 void Insert(int u, int v, int w) 19 { 20 edges[sz].v = v; 21 edges[sz].w = w; 22 edges[sz].nxt = head[u]; 23 head[u] = sz++; 24 } 25 26 int tot; 27 int haha[maxn]; 28 29 void dfs(int u, int fa) 30 { 31 for(int i = head[u]; i != -1; i = edges[i].nxt) 32 { 33 int v = edges[i].v, w = edges[i].w; 34 if(v == fa) continue; 35 dis[v] = dis[u] + w; 36 dfs(v, u); 37 if(vis[v]) { tot += w * 2; vis[u] = true; } 38 } 39 } 40 41 int main() 42 { 43 while(scanf("%d%d", &n, &root) == 2) 44 { 45 sz = 0; 46 memset(head, -1, sizeof(head)); 47 for(int i = 1; i < n; i++) 48 { 49 int u, v, w; scanf("%d%d%d", &u, &v, &w); 50 Insert(u, v, w); 51 Insert(v, u, w); 52 } 53 54 memset(vis, false, sizeof(vis)); 55 scanf("%d", &m); 56 for(int i = 0; i < m; i++) { scanf("%d", haha + i); vis[haha[i]] = true; } 57 58 tot = 0; 59 dis[root] = 0; 60 dfs(root, -1); 61 62 int hehe = 0; 63 for(int i = 0; i < m; i++) hehe = max(hehe, dis[haha[i]]); 64 printf("%d\n", tot - hehe); 65 } 66 67 return 0; 68 }
7.31
HDU 3507 斜率优化 DP Print Article
8.1(又过了一个月,sigh~)
8.2
CodeForces 484B 数学 Maximum Value
HDU 3516 DP 四边形不等式优化 Tree Construction
HDU 3506 DP 四边形不等式优化 Monkey Party
LightOJ 1422 区间DP Halloween Costumes
UVa 11987 并查集 Almost Union-Find
CodeForces 149D 区间DP Coloring Brackets
POJ 1651 区间DP Multiplication Puzzle
8.3
UVa 10534 DP LIS Wavio Sequence
8.4
8.5
UVa 1354 枚举子集 Mobile Computing
UVa 12299 线段树 单点更新 RMQ with Shifts
8.6
SPOJ 375 树链剖分 QTREE - Query on a tree
HDU 3966 RE 树链剖分 Aragorn's Story
POJ 2763 树链剖分 线段树 Housewife Wind
8.10
UVa 11795 状压DP Mega Man's Mission
HDU 1827 强连通 缩点 Summer Holiday
HDU 3072 SCC Intelligence System
8.11
CodeForces 109C 树形DP Lucky Tree
CodeForces 489F DP Special Matrices
CodeForces 519E 树形DP A and B and Lecture Rooms
8.12
HDU 4738 双连通分量 Caocao's Bridges
UVa 12167 & HDU 2767 强连通分量 Proving Equivalences
8.13
UVa 10564 DP Paths through the Hourglass
8.14
HDU 5378 树上的概率DP Leader in Tree Land
8.15
CodeForces 570D DFS序 树状数组 Tree Requests
HDU 5371 Manacher Hotaru's problem
8.17
CodeForces 379F 树的直径 New Year Tree
8.18
8.19
HDU 5402 模拟 构造 Travelling Salesman Problem