agc034E - Complete Compress

题目描述

题解

最水的E题没有之一

枚举最终点,显然可以转化成若干个数,每次把两个数各-1,不能减到负数

那么如果最大数大于剩下的就无解,否则一定有解,具体每次把最大和次大拿出来-1,如果次次大>=2那么仍合法,如果为1且减的两个都为1,那么根据每次-2的原则即总和为偶数还存在另一个1,所以也合法

发现放到树上之后还可能在子树内先消掉一部分,不可能同一个子树内的相互靠近因为不优,所以一定是子树内的朝着子树的根走

设f[i]表示子树i内最小能剩下多少距离和,转移把和最大的子树拉出来判f即可求得当前的f,注意子树内部走最多只能走到子树的根而不是当前的根

时间O(n^2)

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define inf 2147483647
#define ll long long
//#define file
using namespace std;

int a[4001][2],ls[2001],f[2001],sum[2001],sz[2001],len,n,i,j,k,l,ans;
char b[2001];

void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
void dfs(int Fa,int t)
{
	int i,mx=0,Mx,Sum=0,s;
	sz[t]=b[t]=='1',sum[t]=0;
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	{
		dfs(t,a[i][0]);
		s=sum[a[i][0]]+sz[a[i][0]];
		sz[t]+=sz[a[i][0]];
		sum[t]+=s;
		
		Sum+=s;
		if (s>mx) mx=s,Mx=a[i][0];
	}
	
	if (mx && f[Mx]+sz[Mx]>Sum-mx)
	f[t]=f[Mx]+sz[Mx]-(Sum-mx);
	else
	f[t]=sum[t]&1;
}
void work(int t)
{
	int i,j,k,l;
	dfs(0,t);
	if (!f[t]) ans=min(ans,sum[t]/2);
}

int main()
{
	#ifdef file
	freopen("agc034E.in","r",stdin);
	#endif
	
	scanf("%d",&n);
	scanf("%s",b+1);
	fo(i,1,n-1) scanf("%d%d",&j,&k),New(j,k),New(k,j);
	
	ans=inf;
	fo(i,1,n) work(i);
	printf("%d\n",(ans==inf)?-1:ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-10-22 21:41  gmh77  阅读(167)  评论(0编辑  收藏  举报