In mathematics you don't understand things, you just get used to them.

Description

Link.

定义一条链的价值为链上点权乘积除以节链上点数,求一条价值最小的链。

Solution

结论:答案链上最多包含一个 $2$(其余全为 $1$),并且不在链的两端点。

证明:我们问题分成两个 $\texttt{pass}$。

  • $\texttt{pass 1}$:$\forall u,s.t.x_{u}\ge2$。

答案显然为 $\min\{x_{u}\},u\in V$。

  • $\texttt{pass 2}$:$\exists E'\subset E,s.t.x_{u}=1,u\in E'\wedge x_{v}\ge2,v\in E\setminus E'$。
    • 我们设我们选出的链为大概这样的造型:

$$ 1\rightarrow1\rightarrow\cdots\rightarrow X\rightarrow1\rightarrow1\cdots $$

即一堆 $1$ 中夹了一个 $X$。

我们设 $X$ 左边有 $l$ 个节点,右边有 $r$ 个节点。

则价值为整条链 $\frac{X}{l+r+1}$,左边 $\frac{1}{l}$,右边 $\frac{1}{r}$。

为方便我们这里设 $l<r$。

那么左边的价值一定大于右边。

这里假设 $\frac{1}{r}>\frac{X}{l+r+1}$,则有 $X<\frac{l+1}{r}+1$,又 $r\ge l+1$,所以 $\frac{l+1}{r}\le1$。(反之可以证伪,懒得写了 QwQ)

所以有 $X\le2$。

又 $X\neq1$,所以 $X=2$。

    • 我们设我们选出的链为大概这样的造型:

$$ 1\rightarrow1\rightarrow\cdots\rightarrow X\rightarrow1\rightarrow\cdots\rightarrow1\rightarrow Y\rightarrow1\cdots $$

即一堆 $1$ 中夹了一个 $X$ 一个 $Y$。

这里我们可以把 $Y$ 以前当成 $\texttt{pass 2}$ 的第一个类型,设其共有 $N$ 个数。

那么假设我们加入 $Y$ 更优,即有 $\frac{XY}{N+1}<\frac{X}{N}$,则有 $NY<N+1$,由于 $Y\neq1$,所以加入 $Y$ 是更劣的。

后面的同理就可以推广了。

于是得证 QwQ。

然后我们就可以 DP 了。

设 $f_{u,0/1}$ 表示节点 $u$ 权值为的情况下最优答案。

转移就分类讨论一下:

  • $x_{u}=1$

$$ \begin{cases} f_{u,0}=\max\{f_{v,0}\}+1 \\ f_{u,1}=\max\{f_{v,1}\}+1 \end{cases} $$

  • $x_{u}=2$

$$ f_{u,1}=\max\{f_{v,0}\}+1 $$

答案也需要分类讨论(这里设 $x,y\in\text{son}(u)$):

  • $x_{u}=1$

答案为 $\frac{1}{\max\{f_{x,0}+f_{y,0}+1\}}$,以及 $\frac{2}{\max\{f_{x,0}+f_{y,1}\}+1}$。

  • $x_{u}=2$

答案为 $\frac{2}{\max\{f_{x,0}+f_{y,0}+1\}}$。

用四个变量维护最大、次大的 $f_{0},f_{1}$ 即可。

#include <cstdio>

const int MAXN = 1e6 + 5;

int rint () {
    int x = 0, f = 1; char c = getchar ();
    for ( ; c < '0' || c > '9'; c = getchar () )    f = c == '-' ? -f : f;
    for ( ; c >= '0' && c <= '9'; c = getchar () )    x = ( x << 3 ) + ( x << 1 ) + ( c & 15 );
    return x * f;
}

template<typename _T>
void wint ( _T x ) {
    if ( x < 0 )    putchar ( '-' ), x = ~ x + 1;
    if ( x > 9 )    wint ( x / 10 );
    putchar ( x % 10 ^ '0' );
}

template<typename _T> _T MIN ( const _T x, const _T y ) { return x > y ? y : x; }

struct starS {
    int to, nx;
    starS ( int T = 0, int N = 0 ) { to = T, nx = N; }
} as[MAXN * 2];

int n, cnt, Up = 1e9, Dn = 1, mnMg = 1e9, a[MAXN], f[MAXN][2], bgin[MAXN];

void pushEdge ( const int u, const int v ) { as[++ cnt] = starS ( v, bgin[u] ); bgin[u] = cnt; }

void checkUpt ( const int x, const int y ) { if ( Up * y > Dn * x )    Up = x, Dn = y; }

void dfs ( const int u, const int lst ) {
    int mx0 = 0, se0 = 0, mx1 = 0, se1 = 0;
    for ( int i = bgin[u]; i; i = as[i].nx ) {
        int v = as[i].to;
        if ( v == lst )    continue;
        dfs ( v, u );
        if ( f[v][0] > f[mx0][0] )    se0 = mx0, mx0 = v;
        else if ( f[v][0] > f[se0][0] )    se0 = v;
        if ( f[v][1] > f[mx1][1] )    se1 = mx1, mx1 = v;
        else if ( f[v][1] > f[se1][1] )    se1 = v;
    }
    if ( a[u] == 1 ) {
        f[u][0] = f[mx0][0] + 1;
        checkUpt ( 1, f[mx0][0] + f[se0][0] + 1 );
        if ( ! mx1 )    return;
        f[u][1] = f[mx1][1] + 1;
        if ( mx0 != mx1 )    checkUpt ( 2, f[mx0][0] + f[mx1][1] + 1 );
        else {
            checkUpt ( 2, f[se0][0] + f[mx1][1] + 1 );
            if ( se1 )    checkUpt ( 2, f[mx0][0] + f[se1][1] + 1 );
        }
    }
    else if ( a[u] == 2 )    f[u][1] = f[mx0][0] + 1, checkUpt ( 2, f[mx0][0] + f[se0][0] + 1 );
}

int main () {
    n = rint ();
    for ( int i = 1, u, v; i < n; ++ i ) {
        u = rint (), v = rint ();
        pushEdge ( u, v ), pushEdge ( v, u );
    }
    for ( int i = 1; i <= n; ++ i )    a[i] = rint (), mnMg = MIN ( mnMg, a[i] );
    if ( mnMg > 1 )    wint ( mnMg ), putchar ( '/' ), wint ( 1 ), putchar ( '\n' );
    else    dfs ( 1, 0 ), wint ( Up ), putchar ( '/' ), wint ( Dn ), putchar ( '\n' );
    return 0;
}

maths dp trees

Record - Nov. 27st, 2020 - Exam. REC & SOL
上一篇 «
Solution -「洛谷 P3773」「CTSC 2017」吉夫特
» 下一篇