牛客挑战赛52天平
题意:
给一个二叉树有 n n n个节点,这个二叉树中的每个节点有么有2个儿子要么没有儿子。给定 m m m个数,这 m m m个数有任意多个,你可以把每个节点赋值为这 m m m个数中的一个(可以重复使用),整体赋值完后,每个非叶子节点的贡献为 l v lv lv+ r v rv rv,并且满足 s [ l s [ u ] ] × l v = s [ r s [ u ] ] × r v s[ls[u]]\times lv=s[rs[u]]\times rv s[ls[u]]×lv=s[rs[u]]×rv,( s [ l s [ u ] ] , s [ r s [ u ] ] s[ls[u]],s[rs[u]] s[ls[u]],s[rs[u]]为赋值完后的左子树和右子树的点权和),题目要求最小化所有非叶子节点的贡献和。
1 ≤ v ≤ 50 1\le v \le 50 1≤v≤50 1 ≤ n ≤ 50 1\le n \le 50 1≤n≤50
Sol
要使 l v , r v lv,rv lv,rv最小,显然 l v = s [ l s [ u ] ] / g c d ( s [ l s [ u ] ] , s [ r s [ u ] ] ) , r v = s [ r s [ u ] ] / g c d ( s [ l s [ u ] ] , s [ r s [ u ] ] ) lv=s[ls[u]]/gcd(s[ls[u]],s[rs[u]]),rv=s[rs[u]]/gcd(s[ls[u]],s[rs[u]]) lv=s[ls[u]]/gcd(s[ls[u]],s[rs[u]]),rv=s[rs[u]]/gcd(s[ls[u]],s[rs[u]])
记 v a l [ i ] [ j ] = i / ( i , j ) + j / ( i , j ) val[i][j]=i/(i,j)+j/(i,j) val[i][j]=i/(i,j)+j/(i,j)
令 d p [ i ] [ j ] dp[i][j] dp[i][j]表示以 i i i为节点,并且 i i i的子树和包括自身点权为 j j j的最小贡献和
则枚举 m m m个数,记为 a a a,并枚举每一个左右子树和 j j j,则转移为 d p [ i ] [ j + a ] = m i n ( d p [ i ] [ j + a ] , d p [ l s [ u ] ] [ j 1 ] + d p [ r s [ u ] ] [ j 2 ] + v a l [ j 1 ] [ j 2 ] ) dp[i][j+a]=min(dp[i][j+a],dp[ls[u]][j_1]+dp[rs[u]][j_2]+val[j_1][j_2]) dp[i][j+a]=min(dp[i][j+a],dp[ls[u]][j1]+dp[rs[u]][j2]+val[j1][j2]),其中 ( j 1 + j 2 = = j ) (j_1+j_2==j) (j1+j2==j)
(每一个点的子树和上限为 50 ∗ 50 50*50 50∗50,可以每次转移前处理出 d p [ l s [ u ] ] [ j 1 ] + d p [ r s [ u ] ] [ j 2 ] + v a l [ j 1 ] [ j 2 ] dp[ls[u]][j_1]+dp[rs[u]][j_2]+val[j_1][j_2] dp[ls[u]][j1]+dp[rs[u]][j2]+val[j1][j2],则转移为 O ( m ∗ 2500 ) O(m*2500) O(m∗2500))
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=55;
const ll inf=1e18;
int ls[N],rs[N];
ll dp[N][N*N],sz[N];
int a[N];
ll v[N*N][N*N],tmp[N*N];
int n,m;
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
void dfs(int u)
{
sz[u]=1;
if(!ls[u])
{
for(int i=1;i<=50;i++) dp[u][i]=inf;
for(int i=1;i<=m;i++) dp[u][a[i]]=0;
return;
}
dfs(ls[u]),dfs(rs[u]);
sz[u]=sz[u]+sz[ls[u]]+sz[rs[u]];
for(int i=1;i<=sz[u]*50;i++) tmp[i]=inf;
for(int i=1;i<=sz[ls[u]]*50;i++)
for(int j=1;j<=sz[rs[u]]*50;j++)
{
tmp[i+j]=min(tmp[i+j],dp[ls[u]][i]+dp[rs[u]][j]+v[i][j]);
}
for(int i=1;i<=sz[u]*50;i++)
{
dp[u][i]=inf;
for(int j=1;j<=m;j++)
if(i>a[j])dp[u][i]=min(dp[u][i],tmp[i-a[j]]);
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>a[i];
int u,x,y;
for(int i=1;i<=(n-1)/2;i++)
{
cin>>u>>x>>y;
ls[u]=x;
rs[u]=y;
}
for(int i=1;i<=2500;i++)
for(int j=1;j<=2500;j++)
{
int p=gcd(i,j);
v[i][j]=i/p+j/p;
}
dfs(1);
ll ans=inf;
for(int i=1;i<=n*50;i++) ans=min(ans,dp[1][i]);
cout<<ans<<endl;
return 0;
}