【洛谷】P4202 [NOI2008]奥运物流

【洛谷】P4202 [NOI2008]奥运物流

感觉有点降智

首先设环长为\(len\),很容易推导出

\[R(1) = \frac{\sum_{i = 1}^{N} C_{i} k^{dep[i]}}{1 - k^{len}} \]

我好像觉得似乎\(len\)越大底下越小了,太降智了,len越大底下越大

所以环长越小越好,所以我们如果动了一条环边,就是把它尽量往1连

枚举环上,强制要求环上上的点不选,除开1到1的后继的那条边,我们就获得了一棵树

我们希望\(dp\)出改了m个点最大是多少,显然改就一定直接连到1

\(f[u][j][d]\)\(u\)这个点,子树里改了\(j\)个点,我们硬点\(u\)\(1\)的距离是\(d\)

转移的话分\(u\)有没有被连到1

如果被连到1了,那么就从\(max(f[v][k][1],f[v][k][2])\)转移过来,要加上\(C_{u} \times K\)

否则就从\(max(f[v][k][d + 1],f[v][k][1])\)转移过来,要加上\(C_{u} \times K^{d}\)

第二维是个背包,直接做就行了

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define ba 47
#define MAXN 5005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
	if(c == '-') f = -1;
	c = getchar();
    }
    while(c >= '0' && c <= '9') {
	res = res * 10 +c - '0';
	c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
	out(x / 10);
    }
    putchar('0' + x % 10);
}
int N,M;
int fa[65];
db K[65],C[65],f[65][65][65],g[65];
bool nouse[65];
void dfs(int u,int dep) {
    for(int v = 2 ; v <= N ; ++v) {
	if(fa[v] == u) dfs(v,dep + 1);
    }
    for(int d = dep ; d >= min(dep,2) ; --d) {
	memset(g,0,sizeof(g));
	for(int v = 1 ; v <= N ; ++v) {
	    if(fa[v] == u) {
		for(int j = M ; j >= 0 ; --j) {
		    for(int k = j ; k >= 0 ; --k) {
			g[j] = max(g[j],g[k] + max(f[v][j - k][d + 1],f[v][j - k][1]));
		    }
		}
	    }
	}
	for(int j = 0 ; j <= M ; ++j) f[u][j][d] = g[j] + C[u] * K[d];
    }
    if(!nouse[u] && fa[u] != 1) {
	memset(g,0,sizeof(g));
	for(int v = 1 ; v <= N ; ++v) {
	    if(fa[v] == u) {
		for(int j = M ; j >= 0 ; --j) {
		    for(int k = j; k >= 0 ; --k) {
			g[j] = max(g[j],g[k] + max(f[v][j - k][2],f[v][j - k][1]));
		    }
		}
	    }
	}
	for(int j = 0 ; j < M ; ++j) f[u][j + 1][1] = g[j] + C[u] * K[1];
    }
}
void Init() {
    read(N);read(M);scanf("%lf",&K[1]);
    for(int i = 1 ; i <= N ; ++i) {
	read(fa[i]);
    }
    K[0] = 1;
    for(int i = 2 ; i <= N ; ++i) {
	K[i] = K[i - 1] * K[1];
    }
    for(int i = 1 ; i <= N ; ++i) {
	scanf("%lf",&C[i]);
    }
}
void Solve() {
    int p = 1;
    db ans = 0;
    for(int len = 2 ; len ; ++len) {
	p = fa[p];
	if(p == 1) break;
	memset(nouse,0,sizeof(nouse));
	int t = 1,l = 0;
	while(l != len) {
	    nouse[t] = 1;
	    t = fa[t];
	    ++l;
	}
	int rec = 0;
	if(fa[p] != 1) {--M;rec = fa[p];fa[p] = 1;}
	memset(f,0,sizeof(f));
	dfs(1,0);
	db res = f[1][M][0] / (1 - K[len]);
	ans = max(ans,res);
	if(rec) {++M;fa[p] = rec;}
	
    }
    printf("%.2lf\n",ans);
}
int main(){
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
}
posted @ 2019-06-13 10:43  sigongzi  阅读(290)  评论(0编辑  收藏  举报