题解
-
考虑DP。这题首先发现如果修改后继状态那么一定修改成 (1) 。然后现在难点在于如何解决存在一个环的问题以及状态的设计。先考虑是树的情况。
-
可以发现跟IOI河流Riv一题相似,子树内节点的贡献会被祖先的状态影响。这道题中显然每个节点单独的贡献与其深度有关,那么考虑将其计入状态。现在设 (f[u][t][d]) 表示以 (u) 为根的子树内一共有 (t) 个节点将后继修改为 (1) ,且 (u) 此时的深度为 (d) 的最大贡献。那么我们发现对于一对父子 (u,v) ,我们只需特殊处理关于深度为 (1) 的边界状态,然后枚举 (t_u,t_v,d_u) ,再从 (d_v=d_u+1) 或 (d_v=1) 的状态背包转移即可。最后注意每个状态要加上 (C_ucdot k^d) ,也就是 (u) 自身的贡献。
-
那么现在考虑环的问题。若设一个节点的深度为 其在不考虑 (1) 的后继边所形成的树上的深度 ,若环上一点深度为 (d) ,环长为 (len) ,那么环带来的影响其实就是是每个节点单独的贡献多了 (R(1)cdot k^{len}) 。那么等比数列求个和我们会发现若在树的情况下我们求出的答案为 (R') ,那么最终 (R(1)=frac{R'}{1-k^{len}}) 。那么我们直接枚举初始强制将哪一个环上节点的后继修改为 (1) 得到环长 (len) ,然后dp即可。由于题目保证环上节点最多 (20) 个,所有最终复杂度为 (O(20cdot n^2cdot m^2)) ,可以通过此题。
-
注意修改初始将某一个环上节点的后继为 (1) 是强制的,虽然修改后的树中该节点深度为 (1) ,但是如果该节点原来的后继不是 (1) 的话该节点 (t =0,d=1) 的状态不合法,要特判掉。
#include<bits/stdc++.h> #define ll long long #define ull unsigned long long #define rep(i, s, t) for(int i = s, __ = t; i <= __; ++i) #define dwn(i, s, t) for(int i = s, __ = t; i >= __; --i) const int INF = 2147483647; const int MAXN = 100 + 100; const int MOD = 998244353; using namespace std; inline int read(int x = 0, int f = 1){ char ch = getchar(); for(; !isdigit(ch); ch = getchar())if(ch == '-')f = -1; for(; isdigit(ch); ch = getchar())x = ch - '0' + x * 10; return x * f; } inline void write(int x){ if(x < 0)x = -x, putchar('-'); if(x >= 10)write(x / 10); putchar(x % 10 + '0'); return ; } int n, m, fa[MAXN]; double k, C[MAXN]; double dp[MAXN][MAXN][MAXN], sup[MAXN][MAXN], pw[MAXN]; inline void upd(double &x, double y){x = max(x, y); return ;} void dfs(int u){ dp[u][1][1] = C[u] * k; if(dp[u][0][1] != -INF + 1){ rep(d, 2, n)dp[u][0][d] = C[u] * pw[d]; if(fa[u] == 1)dp[u][0][1] = C[u] * k; } rep(v, 2, n)if(fa[v] == u){ dfs(v); rep(i, 0, m)rep(j, 1, n)sup[i][j] = -INF; rep(i, 0, m)rep(j, 0, m){ rep(d, 1, n){ if(i + j > m)break; upd(sup[i + j][d], dp[u][i][d] + max(dp[v][j][d + 1], dp[v][j][1])); } } rep(i, 0, m)rep(d, 0, n)dp[u][i][d] = sup[i][d]; } return ; } double f[MAXN], ans = 0; int main(){ n = read(), m = read(), scanf("%lf", &k); rep(i, 1, n)fa[i] = read(); rep(i, 1, n)scanf("%lf", &C[i]); pw[0] = 1.0; rep(i, 1, n)pw[i] = pw[i - 1] * k; int cur = fa[1], cnt = 2; while(cur != 1){ rep(i, 1, n)rep(j, 0, m)rep(k, 1, n)dp[i][j][k] = -INF; rep(i, 0, m)f[i] = -INF; f[0] = 0; int up = fa[cur]; fa[cur] = 1; int tag = 0; if(up != 1)tag = 1, dp[cur][0][1] = -INF + 1, dfs(cur); rep(v, 2, n)if(fa[v] == 1 && (v != cur || !tag)){ dfs(v); dwn(h, m, 0){ dwn(i, h, 0){ int j = h - i; upd(f[h], f[i] + dp[v][j][1]); } } } if(tag){ f[m] = f[m - 1] + dp[cur][1][1]; rep(i, 0, m - 2)upd(f[m], f[i] + dp[cur][m - i][1]); } ans = max(ans, (f[m] + C[1]) / (1.0 - pw[cnt])); fa[cur] = up, ++cnt, cur = up; } printf("%.2lf", ans); return 0; }