P1411 树(dp)

令 d p ( i , j ) dp(i,j) dp(i,j) 表示结点 i i i 所在连通块大小为 j j j的答案。

对于结点 u u u的儿子结点 v v v,有转移方程:

d p ( u , j ) = m a x ( d p ( u , j ) , d p ( u , k ) × d p ( v , j − k ) k × ( j − k ) × j ) dp(u,j)=max(dp(u,j),\dfrac{dp(u,k)\times dp(v,j-k)}{k\times (j-k)}\times j) dp(u,j)=max(dp(u,j),k×(j−k)dp(u,k)×dp(v,j−k)×j)

因为有答案要用高精度。不妨

令 d p ′ ( u , j ) = d p ( u , j ) j dp'(u,j)=\dfrac{dp(u,j)}{j} dp′(u,j)=jdp(u,j)

这样 d p ′ ( u , j ) = m a x ( d p ′ ( u , j ) , d p ′ ( u , k ) × d p ′ ( v , k ) ) dp'(u,j)=max(dp'(u,j),dp'(u,k)\times dp'(v,k)) dp′(u,j)=max(dp′(u,j),dp′(u,k)×dp′(v,k))

最后答案就是: m a x ( d p ( 1 , i ) × i ) max(dp(1,i)\times i) max(dp(1,i)×i)

不妨令 d p ( i , 0 ) = m a x ( d p ( 1 , i ) × i ) dp(i,0)=max(dp(1,i)\times i) dp(i,0)=max(dp(1,i)×i)

这样就方便转移了。

时间复杂度: O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=705,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = {402653189,805306457,1610612741,998244353};
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
template <typename T> //x=max(x,y) x=min(x,y)
void cmx(T &x,T y){
if(x<y) x=y;
}
template <typename T>
void cmn(T &x,T y){
if(x>y) x=y;
}
struct num{
int len,c[1005];
num(){
len=0,mst(c,0);
} //no parameter init
num(int x){ mst(c,0);//init by number
if(!x) len=1;
else{len=0;while(x) c[++len]=x%10,x/=10;}
}
num operator +(const num &b)const{ //高精加
num ans(0);
int l=max(len,b.len),p=0;
ans.len=l;
for(int i=1;i<=l;i++){
ans.c[i]=c[i]+b.c[i]+p;
p=ans.c[i]/10;
ans.c[i]%=10;
}
if(p) ans.c[++ans.len]=p;
return ans;
}
num operator *(const num &b)const{ //高精乘高精
num ans(0);
int l=len+b.len-1,p=0;
for(int i=1;i<=len;i++)
for(int j=1;j<=b.len;j++)
ans.c[i+j-1]+=c[i]*b.c[j];
for(int i=1;i<=l;i++){
ans.c[i+1]+=ans.c[i]/10;
ans.c[i]%=10;
}
if(ans.c[l+1]) l++;ans.len=l;
return ans;
}
num operator *(int &x){ //高精乘低精
int p=0;
for(int i=1;i<=len;i++){
c[i]=c[i]*x+p;
p=c[i]/10;
c[i]%=10;
}
while(p){
c[++len]=p;
p/=10;
c[len]%=10;
}
return *this;
}
};
void Print(num a){
while(!a.c[a.len]&&a.len>1) a.len--;
for(int i=a.len;i;i--)
printf("%d",a.c[i]);
printf("\n");
}
bool jg(num a,num b){ //高精度比较
if(a.len!=b.len) return a.len<b.len;
else for(int i=1;i<=a.len;i++)
if(a.c[i]!=b.c[i])
return a.c[i]<b.c[i];
return 0;
}
void Ckmx(num &a,num b){
if(jg(a,b)) a=b;
}
vector<int>e[N];
num dp[N][N],one;
int sz[N];
void dfs(int u,int fa){
sz[u]=1,dp[u][0]=dp[u][1]=one;
if(u==1) Print(dp[u][1]);
for(int v:e[u]){
if(v==fa) continue;
dfs(v,u);sz[u]+=sz[v];
for(int i=sz[u];i;i--){
for(int j=min(i,sz[u]-sz[v]);j>=max(1,i-sz[v]);j--){
if(u==1&&j==1){
printf("v=%d\n",v);
Print(dp[v][i-j]);
}
Ckmx(dp[u][i],dp[u][j]*dp[v][i-j]);
}
}
}
/*printf("u=%d\n",u);
Print(dp[u][1]);*/
rep(i,1,sz[u]) {
/*if(u==1){
Print(dp[u][i]);
printf("i=%d\n",i);
puts("---------------");
}*/
Ckmx(dp[u][0],dp[u][i]*i);
}
/*printf("u=%d sz=%d\n",u,sz[u]);
Print(dp[u][0]);
puts("-------------");*/
}
int main(){
int n;scanf("%d",&n);
one = num(1);
/*Print(one);
puts("----------");*/
rep(i,1,n-1){
int u,v;scanf("%d%d",&u,&v);
e[u].pb(v),e[v].pb(u);
}
dfs(1,0);
Print(dp[1][0]);
return 0;
}