首页 > 代码库 > Apple Tree
Apple Tree
题意:
给一有根树,每个叶子上有一些苹果,现在要求你拿掉一些苹果,使得每一个点的 儿子的子树内的苹果数相同。
解法:
首先可以发现$cnt$个叶子节点之间的关系可以用$cnt-1$个独立方程表示出来。
这样相当于在方程的解中只有一个变元。
接下来求出最小整数基底:这个我们可以两遍$dfs$ + $gcd$求出。
总效率$O(nlogn)$
#include <iostream> #include <cstdio> #include <cstring> #define LL long long #define N 100010 #define INF 0x3f3f3f3f3f3f3f3fLL using namespace std; struct edge { int x,to; }E[N<<1]; int n,totE; int g[N]; LL f[N],a[N],sum; bool is_leaf[N]; void addedge(int x,int y) { E[++totE] = (edge){y,g[x]}; g[x]=totE; E[++totE] = (edge){x,g[y]}; g[y]=totE; } LL gcd(LL a,LL b) { if(!b) return a; return gcd(b,a%b); } #define p E[i].x LL calc(int x,int tp) { int cnt=0; LL ans=1; for(int i=g[x];i;i=E[i].to) if(p!=tp) { LL tmp = calc(p,x); cnt++; if(ans/gcd(ans,tmp)<=sum/tmp) ans = ans/gcd(ans,tmp)*tmp; else return -1; } if(!cnt) { is_leaf[x]=1; return 1LL; } if(ans<=sum/cnt) return ans*(LL)cnt; else return -1; } void dfs(int x,int tp) { int cnt=0; for(int i=g[x];i;i=E[i].to) if(p!=tp) cnt++; for(int i=g[x];i;i=E[i].to) if(p!=tp) { f[p]=f[x]/(LL)cnt; dfs(p,x); } } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) g[i]=0,is_leaf[i]=0; totE=0; sum=0; for(int i=1;i<=n;i++) scanf("%I64d",&a[i]),sum+=a[i]; for(int i=1,x,y;i<n;i++) { scanf("%d%d",&x,&y); addedge(x,y); } f[1]=calc(1,1); if(f[1]==-1) { cout << sum << endl; continue; } dfs(1,1); LL t=INF, ans=0; for(int i=1;i<=n;i++) if(is_leaf[i]) { ans += a[i]; t = min(t, a[i]/f[i]); } ans -= t*f[1]; cout << ans << endl; } return 0; } /* t*A_i <= B_i(原先的) t <= B_i/A_i */
Apple Tree
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。