题目
解说
题目麻烦的一批。下面直接给简化版:
给一棵树,每个点有一个权值,要求修改一些点的权值,使得:
①同一个父亲的儿子权值必须相同
②父亲的取值必须是所有儿子权值之和
问最小要修改几个点。
很显然这是一个树形DP。
由于这个要求,树上只要有一个点确定,全树的权值就都确定了。那么我们只要计算将路径上权值的累乘积和计算到这里度的累乘积即为(f[i]),(f[i])相同的表示他们同属于同一种合法方案,最后(sort)一遍寻找相同最多的即可。最后输出(n-maxn)。
注意将所有权值累乘会爆(long long),但使用高精度太麻烦,巧妙运用(log)转为加法。(小技巧)
代码
#include<bits/stdc++.h>
using namespace std;
const double minn=1e-6;
const int maxn=500000+3;
struct node {
int to,next;
}a[maxn*2];
double val[maxn];
int v[maxn],head[maxn],s[maxn],cnt;
void add(int x,int y){
a[++cnt].next=head[x];
a[cnt].to=y;
head[x]=cnt;
}
void dfs(int x,int fa,double ans){
val[x]=ans+log(v[x]),s[x]--;
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
if(v==fa) continue;
dfs(v,x,ans+log(s[x]));
}
}
int main(){
ios::sync_with_stdio(false);
int n,x,y,maxx=0,js=1;
cin>>n;
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<n;i++){
cin>>x>>y;
add(x,y);
add(y,x);
s[x]++;
s[y]++;
}
s[1]++;
dfs(1,0,0);
sort(val+1,val+1+n);
for(int i=2;i<=n;i++){
if(val[i]-val[i-1]<minn) js++;//注意double的比较方式
else maxx=max(maxx,js),js=1;
}
cout<<n-maxx;
}
幸甚至哉,歌以咏志。