记录编号 87237 评测结果 AAAAAAAAAA
题目名称 [NOI 2008]奥运物流 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.390 s
提交时间 2014-02-03 08:34:34 内存使用 5.55 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
const int SIZEN=70;
int N,M;
double K;
int father[SIZEN]={0};
vector<int> son[SIZEN];
double C[SIZEN]={0};
double f[SIZEN][SIZEN][SIZEN]={0};
double g[SIZEN][SIZEN][SIZEN]={0};
double powK[SIZEN]={1};
int X;//当前接到1上的环上的点
void DP(int u,int maxd){//对结点u,计算所有离根不超过maxd的f值
	for(int i=0;i<son[u].size();i++) if(son[u][i]!=X&&son[u][i]!=1) DP(son[u][i],maxd+1);
	for(int d=1;d<=maxd;d++){
		int nowchange;
		if(maxd>1&&d==1) nowchange=1;//耗费了一次修改机会来把当前点挂在根上
		else nowchange=0;//当前的点没有修改,而是当前点的某个祖先修改了,此时u并不耗费修改机会
		double F[SIZEN]={0};
		for(int i=0;i<son[u].size();i++){
			int v=son[u][i];
			if(v==X||v==1) continue;//1到其父亲的边无效,X到其父亲的边无效(因为X的父亲已经改成了1)
			for(int j=M;j>=0;j--){//一个v只能更新一次,诸如"v改两次"和"v改三次"不能作为不同的物品
				for(int k=j;k>=0;k--) F[j]=max(F[j],F[k]+g[v][j-k][d]);//背包
			}
		}
		for(int i=nowchange;i<=M;i++) f[u][i][d]=F[i-nowchange]+C[u]*powK[d];//加上自己带来的可靠度
	}
	for(int j=0;j<=M;j++){//方便后面计算
		for(int d=0;d<maxd;d++)	g[u][j][d]=max(f[u][j][d+1],f[u][j][1]);
	}
}
void work(void){
	int len=2;
	double ans=0;
	for(X=father[1];X!=1;X=father[X],len++){//枚举从环上接到1的点
		memset(f,0,sizeof(f));
		memset(g,0,sizeof(g));
		for(int i=2;i<=N;i++) if(father[i]==1||i==X) DP(i,1);
		double F[SIZEN]={0};
		for(int i=2;i<=N;i++){
			if(!(father[i]==1||i==X)) continue;
			for(int j=M;j>=0;j--){
				for(int k=j;k>=0;k--) F[j]=max(F[j],F[k]+f[i][j-k][1]);//背包
			}
		}
		int leftchange;
		if(father[X]==1) leftchange=M;//如果X的父亲是1,那么不必修改X
		else leftchange=M-1;//否则,X用掉了一次修改机会
		for(int i=0;i<=leftchange;i++) ans=max(ans,(F[i]+C[1])/(1-powK[len]));
		/*
		这里认为环长是len.即使DP的决策中将某个环上的点挂到了1从而导致环长不是len
		(一定小于len),也不会影响结果,因为环长长时1-K^len较大,结果显然没有枚举到
		将那个点直接挂在1上时优
		*/
	}
	printf("%.2lf",ans);
}
void read(void){
	scanf("%d%d%lf",&N,&M,&K);
	for(int i=1;i<=N;i++) powK[i]=powK[i-1]*K;
	for(int i=1;i<=N;i++){
		scanf("%d",&father[i]);
		son[father[i]].push_back(i);
	}
	for(int i=1;i<=N;i++) scanf("%lf",&C[i]);
}
int main(){
	freopen("trans.in","r",stdin);
	freopen("trans.out","w",stdout);
	read();
	work();
	return 0;
}