AGC034E
虽然做法大致相同,但是本篇题解将会讲述如何想出正解,分享我的思路。望通过。
首先看到题目,容易想到一个简单很多的情况:在一条链上,且终点确定。此时就可以把终点两边的点分开,分别计算到终点的距离之和,看是否相等即可。
没有确定终点时,枚举一个终点即可。
考虑将这种做法带入本题。先
此时发现没什么突破口,于是开始找性质。我们称一个棋子
Lemma 1:用一个
Proof:首先,进行这样的操作之后
经过思考可以发现,
Lemma 2:如果只考虑以
Proof:如果先找一个子树外的点和一个子树内的点操作,可能子树内原有
再回到题目,由于 Lemma 2,我们是从一个子树再向外操作,很容易想到树形 dp。问题就在于怎样定义状态。
考虑记录经过若干次操作,子树内棋子到根
因为写太久了所以不作讲解。对于
总复杂度
code:
点击查看代码
int n,m,c[N],siz[N];
ll f[N],g[N];
char s[N];
int tot,head[N];
struct node{int to,nxt;}e[N<<1];
il void add(int u,int v){e[++tot]={v,head[u]},head[u]=tot;}
void dfs(int u,int fa){
siz[u]=c[u];
ll s=0,mx=0;
go(i,u){
int v=e[i].to;
if(v==fa)continue;
dfs(v,u);
mx=max(mx,f[v]+siz[v]);
g[u]+=g[v]+siz[v];
siz[u]+=siz[v];
}
go(i,u){
int v=e[i].to;
if(v==fa)continue;
s+=min(g[v]+siz[v],mx);
}
if(s>=2*mx)f[u]=g[u]&1;
else f[u]=2*mx-s;
}
void Yorushika(){
scanf("%d%s",&n,s+1);
rep(i,1,n-1){
int u,v;scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
rep(i,1,n)c[i]=s[i]-'0';
ll ans=1ll*inf*inf;
rep(i,1,n){
mems(f,0),mems(g,0);now=i;
dfs(i,0);
if(!f[i])ans=min(ans,g[i]/2);
}
printf("%lld\n",ans>1e15?-1:ans);
}
signed main(){
int t=1;
// scanf("%d",&t);
while(t--)
Yorushika();
}