WrongAnswer_90

一言(ヒトコト)

P1411 树

P1411 树

更好的阅读体验

简单 DP,但是毒瘤。开高精还卡空间。。

树形 DP。只关心根节点所处连通块大小,自然记 \(f_{i,j}\) 表示以 \(i\) 为根的子树中和 \(i\) 联通的 \(j\) 个点的贡献还没有被计算的答案。这里没有被计算的意思是实际的值为 \(j\times f_{i,j}\),只计算了其他连通块的贡献。转移类似树形背包,两种情况:断 \((i,to)\) 边和保留。

断边的转移方程为:

\[ f_{i,j}=\max_{k=1}^{siz_{to}}\{f_{i,j}\times kf_{to,k}\} \]

保留边的转移方程为:

\[ f_{i,j}=\max_{k=1}^{siz_i}\{f_{i,k}\times f_{to,j-k}\} \]

最后答案即为 \(\max_{k=1}^{n}\{k\times f_{1,k}\}\)

要开高精,支持高精乘高低精和比较大小,复杂度应当是大常数(因为高精) \(\mathcal O(n^2)\),跑的飞快。

	int cnt,n,siz[710],head[710],to[1410],nex[1410];
	inline void add(int x,int y){to[++cnt]=y,nex[cnt]=head[x],head[x]=cnt;}
	namespace BigNum
	{
		struct Node{short len,a[121];Node(){len=0,memset(a,0,sizeof(a));}}f[701][701],tmp[710],ans;
		Node max(Node nd1,Node nd2)
		{
			if(nd1.len>nd2.len)return nd1;
			if(nd1.len<nd2.len)return nd2;
			for(int i=nd1.len;i>=1;--i)
			{
				if(nd1.a[i]>nd2.a[i])return nd1;
				if(nd1.a[i]<nd2.a[i])return nd2;
			}
			return nd1;
		}
		Node operator *(const Node nd1,const int k)
		{
			Node nd3;nd3.len=nd1.len;
			for(int i=1;i<=nd1.len;++i)nd3.a[i]=nd1.a[i]*k;
			for(int i=1;i<=nd1.len;++i)nd3.a[i+1]+=nd3.a[i]/10,nd3.a[i]%=10;
			while(nd3.a[nd3.len+1])++nd3.len,nd3.a[nd3.len+1]+=nd3.a[nd3.len]/10,nd3.a[nd3.len]%=10;
			return nd3;
		}
		Node operator *(const Node nd1,const Node nd2)
		{
			Node nd3;nd3.len=nd1.len+nd2.len-1;
			for(int i=1;i<=nd1.len;++i)
			{
				for(int j=1;j<=nd2.len;++j)
				nd3.a[i+j-1]+=nd1.a[i]*nd2.a[j];
			}
			for(int i=1;i<=nd3.len;++i)nd3.a[i+1]+=nd3.a[i]/10,nd3.a[i]%=10;
			while(nd3.a[nd3.len+1])++nd3.len,nd3.a[nd3.len+1]+=nd3.a[nd3.len]/10,nd3.a[nd3.len]%=10;
			return nd3;
		}
	}
	using namespace BigNum;
	void dfs(int x,int fa)
	{
		siz[x]=1;f[x][1].a[f[x][1].len=1]=1;
		for(int i=head[x];i;i=nex[i])
		{
			if(to[i]==fa)continue;
			dfs(to[i],x);
			memcpy(tmp,f[x],sizeof(tmp));
			Node maxn;
			for(int k=1;k<=siz[to[i]];++k)
			maxn=max(maxn,f[to[i]][k]*k);
			for(int j=1;j<=siz[x];++j)
			{
				for(int k=1;k<=siz[to[i]];++k)
				f[x][j+k]=max(f[x][j+k],tmp[j]*f[to[i]][k]);
				f[x][j]=max(f[x][j],tmp[j]*maxn);
			}
			siz[x]+=siz[to[i]];
		}
	}
    inline void mian()
    {
    	read(n);int x,y;
    	for(int i=1;i<n;++i)read(x,y),add(x,y),add(y,x);
    	dfs(1,0);
    	for(int i=1;i<=n;++i)
		ans=max(ans,f[1][i]*i);
    	for(int i=ans.len;i>=1;--i)write(ans.a[i],'~');
	}
posted @ 2023-11-01 21:50  WrongAnswer_90  阅读(20)  评论(0编辑  收藏  举报