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;
}