2024杭電多校第9場

Aderose_yr發表於2024-08-20

9

1001 樹異或價值 (hdu7529

對價值定義式進行轉化,\((a_i\oplus a_j)\times lca(a_i, a_j)\) 可視為 \(a_i,a_j\) 的所有祖先下 \(\sum a_i\oplus a_j\),陣列 \(a\) 總價值即各節點子樹中任意兩個子節點的異或之和。由按位異或的性質,不同二進位制位之間答案互不影響,可簡化考慮最低位即 \(a_i\in \{0, 1\}\),計算出此時的 \(ans'\),有 \(ans = (ans')^k\).

\(a_i\in \{0, 1\}\) 時,為了使異或之和儘可能大,即各節點子樹內 \((\sum [a=0])\times (\sum [a=1])\) 最大,應使 \(a = 0\)\(a = 1\) 子節點數量儘可能平均;實際上透過構造可實現所有節點下 \(\mid\sum[a = 0] - \sum[a = 1])\mid\space \leq 1\). 設 \(dp_x\)\(a_x = 0\) 時子樹符合條件的答案數,\(y\in subtree(x)\)\(se_x,so_x\)分別代表大小為偶數/奇數的 \(y\) 數量,則有:

\(dp_x =\prod dp_y \times 2^{se_x}\times (\dbinom{so_x}{\lfloor\frac{so_x}{2}\rfloor} + \dbinom{so_x}{\frac{so_x}{2} - 1}\times [2|so_x])\).

最終答案即 \((2\times dp_1)^k\). 組合數學的邏輯多少有點抽象,建個模理解一下式子就好,至少程式碼不難寫。

void pre(int i) {
    sz[i] = 1;
    s0[i] = s1[i] = 0;
    for(int j = 0; j < v[i].size(); j++) {
        int t = v[i][j];
        pre(t);
        sz[i] += sz[t];
        if(sz[t] & 1) s1[i]++;
        else s0[i]++;
    }
}
void cal(int i) {
    dp[i] = 1;
    for(int j = 0; j < v[i].size(); j++) {
        int t = v[i][j];
        cal(t);
        dp[i] *= dp[t];
        dp[i] %= mo;
    }
    dp[i] *= fp(2, s0[i]);
    dp[i] %= mo;
    dp[i] *= (c(s1[i], s1[i] / 2) + ((s1[i] & 1) == 0) * c(s1[i], s1[i] / 2 - 1)) % mo;
    dp[i] %= mo;
}

1003 黑洞合併 (hdu7531

真抽象啊,這個《規律》是賽時我發現了都不敢提出來的程度。把它寫這裡純粹是為了紀念我寫過這麼一道抽象的題目()

1006 融合礦石 (hdu7534

非常巧妙的dp. 資料保證隨著金輝石佔比的增加,礦石價值單調不減,且礦石的數量無限,因此用完全揹包預處理出所有可能的融合情況下、一定質量礦石的最大金輝石含量,將結果看作 \(m\) 種不同的新礦石,再用一次完全揹包計算即可。

    for(int i = 1; i <= n; i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        for(int j = a; j <= m; j++) {
            f[j] = max(f[j], f[j - a] + b);
        }
    }
    for(int i = 1; i <= m; i++) {
        if(!f[i]) continue;
        int x = (f[i] * 10 - 1) / i + 1;
        f[i] = v[x] * i;
    }
    for(int i = 1; i <= m; i++) {
        for(int j = i; j <= m; j++) {
            g[j] = max(g[j], g[j - i] + f[i]);
        }
    }
    printf("%lld\n", g[m]);

相關文章