zoukankan      html  css  js  c++  java
  • [NOI2008]奥运物流

    • 题目链接:洛谷BZOJ

    • 前置知识:莫得

    题解

    • 考虑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;
      }
      
  • 相关阅读:
    CSDN工具-CSDN信息查看
    Plaintext Encryption
    摆脱任何工具-简单代码让文件夹加密
    pyquery解析库
    beautifulsoup解析库
    lxml beautiful pyquery三种解析库
    python的enumerate lambda isinstance filter函数
    python字符串的split replace strip
    整理github总结
    简单python爬虫实例
  • 原文地址:https://www.cnblogs.com/gdc-destinies/p/11321604.html
Copyright © 2011-2022 走看看