# Codeforces Round #664 (Div. 1) 部分简要题解

### A

int n,d,m,m1,m2,a[N],b[N];
ll s1[N],s2[N];

int main()
{
rep(i,1,n)
{
if (x>m) a[++m1]=x;
else b[++m2]=x;
}
sort(a+1,a+1+m1);sort(b+1,b+1+m2);
reverse(a+1,a+1+m1);reverse(b+1,b+1+m2);
ll ans=0;
rep(i,1,m1) s1[i]=s1[i-1]+a[i];
rep(i,1,m2) s2[i]=s2[i-1]+b[i];
rep(i,0,m2)
{
ll now=s2[i];
int rst=(n-i-1)/(d+1)+1;
//cout << i << " " << rst << endl;
now+=s1[min(rst,m1)];
ans=max(now,ans);
}
printf("%lld\n",ans);
return 0;
}


### B

int n,m,k,up,c[10],len[10][10],ans=0;
vector<pii> edge[10][10],sq[N];
bool cant[10][10][10][10],ban[10][10];
bitset<N> in[10][10],out[10][10];

void dfs(int dep,int sum)
{
if (dep>k) {ans+=(sum==n);return;}
rep(i,1,dep)
{
if (ban[dep][i]) continue;
int ok=1;
rep(j,1,dep-1)
{
if (cant[j][c[j]][dep][i]) {ok=0;break;}
}
if (!ok) continue;
c[dep]=i;
dfs(dep+1,sum+len[dep][i]);
}
}

int main()
{
rep(i,1,m)
{
sq[u].pb(mkp(w,v));
}
rep(u,0,n-1)
{
int d=sq[u].size();
sort(sq[u].begin(),sq[u].end());
rep(j,1,d)
{
int v=sq[u][j-1].sec,w=sq[u][j-1].fir;
edge[d][j].pb(mkp(u,v));
}
}
rep(d,1,k) rep(i,1,d)
{
len[d][i]=edge[d][i].size();
rep(j,0,len[d][i]-1)
{
int u=edge[d][i][j].fir,v=edge[d][i][j].sec;
if ((in[d][i][v]) || (out[d][i][u])) {ban[d][i]=1;break;}
in[d][i][v]=1;out[d][i][u]=1;
}
}
rep(d1,1,k) rep(i1,1,d1)
{
if (ban[d1][i1]) continue;
rep(d2,d1+1,k) rep(i2,1,d2)
{
if (ban[d2][i2]) continue;
if (((in[d1][i1]&in[d2][i2]).any()) || ((out[d1][i1]&out[d2][i2]).any())) cant[d1][i1][d2][i2]=1;
}
}
dfs(1,0);
printf("%d",ans);
return 0;
}


### C

$\begin{cases} \max(|x_1-x_2|,|y_1-y_2|) & \mathrm{sgn}(x1-x2)=\mathrm{sgn}(y_1-y_2)\\ |x_1-x_2|+|y_1-y_2|& \mathrm{sgn}(x1-x2)\neq \mathrm{sgn}(y_1-y_2) \end{cases}$

int n,x[N],y[N];
char s[N];

int chk(int mid)
{
int xl=0,xr=1e9,yl=0,yr=1e9,mnd=-1e9,mxd=1e9;
rep(i,1,n)
{
xl=max(xl,x[i]-mid);xr=min(xr,x[i]+mid);
yl=max(yl,y[i]-mid);yr=min(yr,y[i]+mid);
mnd=max(mnd,y[i]-x[i]-mid);
mxd=min(mxd,y[i]-x[i]+mid);
}
rep(i,xl,xr)
{
int l=max(yl,i+mnd),r=min(yr,i+mxd);
l=max(0,l);
if ((!i) && (!r)) continue;
if (l<=r) return 1;
}
return 0;
}

void chk2(int mid)
{
int xl=0,xr=1e9,yl=0,yr=1e9,mnd=-1e9,mxd=1e9;
rep(i,1,n)
{
xl=max(xl,x[i]-mid);xr=min(xr,x[i]+mid);
yl=max(yl,y[i]-mid);yr=min(yr,y[i]+mid);
mnd=max(mnd,y[i]-x[i]-mid);
mxd=min(mxd,y[i]-x[i]+mid);
}
rep(i,xl,xr)
{
int l=max(yl,i+mnd),r=min(yr,i+mxd);
l=max(0,l);
if ((!i) && (!r)) continue;
if (l<=r)
{
rep(j,1,i) putchar('B');
rep(j,1,r) putchar('N');
return;
}
}
}

int main()
{
rep(i,1,n)
{
scanf("%s",s+1);
int m=strlen(s+1);
rep(j,1,m)
{
if (s[j]=='B') x[i]++;else y[i]++;
}
}
int l=0,r=1e9,ans=0;
while (l<=r)
{
int mid=(l+r)>>1;
if (chk(mid)) {ans=mid;r=mid-1;}
else l=mid+1;
}
printf("%d\n",ans);
chk2(ans);
return 0;
}


### D

$f_{u,0/1}$表示已处理完子树$u$的所有边，且$u\to fa_u$的边是向下/上的最小的t之和。注意到子树的根$u$的贡献只与状态的第二维和它儿子中向上走的个数有关，故在当前状态合法时，可以先强制所有边均是从u向下走的，再枚举有几个儿子为向上走（这一部分的$f_v$的贡献可以由贪心算出），再尽可能的合并路径后算出$t_u$的贡献。

struct node{int to,nxt;}sq[N<<1];
{
}

int n,h[N],t[N];
ll f[N][2];

void dfs(int u,int fu)
{
vl g;g.clear();ll sum=0;
go(u,i)
{
if (v==fu) continue;
dfs(v,u);
sum+=f[v][0];
g.pb(f[v][1]-f[v][0]);
}
sort(g.begin(),g.end());
int m=g.size();ll tmp=sum;
if ((!fu) || (h[u]<=h[fu]))
{
f[u][0]=tmp+1ll*t[u]*max(m,1);
rep(i,1,m)
{
tmp+=g[i-1];
f[u][0]=min(f[u][0],tmp+1ll*t[u]*max(m-i,i+(fu>0)));
}
}
else f[u][0]=1e12;
tmp=sum;
if ((!fu) || (h[u]>=h[fu]))
{
f[u][1]=tmp+1ll*t[u]*(m+(fu>0));
rep(i,1,m)
{
tmp+=g[i-1];
f[u][1]=min(f[u][1],tmp+1ll*t[u]*max(m-i+(fu>0),i));
}
}
else f[u][1]=1e12;
}

int main()
{