[SCOI2006]zh_tree

link

一道并不难的树形DP。

由于中序遍历一定,每颗子树内的节点编号一定是连续的。所以考虑枚举根节点,然后递归处理左右两棵子树,求出最小答案后更新即可。数据范围很小,不用做什么优化,把所有状态记录下来记忆化搜索即可。\(O(N^4)\) 可以水过去。

还有对数据与题目描述严重不符的强烈抗议。

#include<bits/stdc++.h>
//#define feyn
const int N=50;
using namespace std;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}

int m,pl[N][N][N];
double A,B,a[N],sum,g[N][N][N];//deep,l,r
bool vis[N][N][N];

inline double f(int d,int l,int r){
	if(l==r)return (A*d+B)*a[l]/sum;
	if(l>r)return 0;
	if(vis[d][l][r])return g[d][l][r];
	g[d][l][r]=1e9;vis[d][l][r]=true;
	for(int i=l;i<=r;i++){
		double now=(A*d+B)*a[i]/sum+f(d+1,l,i-1)+f(d+1,i+1,r);
		if(now<g[d][l][r])g[d][l][r]=now,pl[d][l][r]=i;
	}
	return g[d][l][r];
}
void print(int d,int l,int r){
	if(l==r){printf("%d ",l);return;}
	if(l>r)return;
	printf("%d ",pl[d][l][r]);
	print(d+1,l,pl[d][l][r]-1);
	print(d+1,pl[d][l][r]+1,r);
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);scanf("%lf%lf",&A,&B);
	for(int i=1;i<=m;i++){
		scanf("%lf",&a[i]);
		sum+=a[i];
	}
	printf("%.3f\n",f(1,1,m));
	//print(1,1,m);
	
	return 0;
}
posted @ 2022-07-06 14:10  Feyn618  阅读(8)  评论(0编辑  收藏  举报