ARC100E Or Plus Max

ARC100E Or Plus Max

位运算上的比大小问题通常都很难处理,因此一般都是先把这种条件转化。

考虑下面三个集合:

  • AK={(i,j) iorjKij}A_K = \{(i, j) \mathop | i \operatorname{or} j \le K \land i \ne j\}
  • BK={(i,j) i,jKij}B_K = \{(i, j) \mathop | i, j \subseteq K\land i \ne j\}
    • 这里 iKi \subseteq K 的意思,可以用以下四种等价角度理解:
    • ibitandK=ii \operatorname{bitand} K = ibitand\operatorname{bitand} 是按位与的意思。
    • 同一个二进制位上,ii 的这一位小于等于 KK 的这一位。
    • 同一个二进制位上,KK 这一位为 11,则 ii 这一位可以为 1100KK 这一位为 00,则 ii 这一位只能为 00
    • ii 的所有为 11 的二进制位数集,是 KK 的所有为 11 的二进制位数集的子集。
  • CK={(i,j) iorj=Kij}C_K = \{(i, j)\mathop | i \operatorname{or} j = K\land i \ne j\}

不难发现 CKBKAKC_K \subseteq B_K \subseteq A_K,以及 AK=i=1KCiA_K = \bigcup\limits_{i=1}^K C_i

不难发现 i=1KCii=1KBi\bigcup\limits_{i=1}^K C_i \subseteq \bigcup\limits_{i=1}^K B_i,而 i=1KBiAK\bigcup\limits_{i=1}^K B_i \subseteq A_K。所以,AK=i=1KBiA_K = \bigcup \limits_{i = 1}^KB_i。唯一不同点在于,原先 CiC_i 之间互不相交,而 BiB_i 有交。

用语言说明这个转化的正确性:BiB_i 包含满足 iorj=Ki \operatorname{or} j = K 的全部 (i,j)(i, j),也不把 iorj>Ki \operatorname{or} j >K(i,j)(i, j) 给放进来,所以正确。

为什么要这么转化?两个原因。

【原因一】

原先 iorjKi \operatorname{or} j \le Kiorj=Ki \operatorname{or} j = K 都是一条二元制约关系。

i,jKi, j \subseteq K 可以理解为 iKjKi \subseteq K \land j \subseteq K,即两条一元制约关系,会更好处理。

当然一直还有一个二元制约关系是 iji \ne j,不过这个通常也不难处理。

【原因二】

iKi \subseteq K 是一个套路性的 sosdp 形式。

不难发现 max\max 是可重复贡献的(即 max(x,x)=x\max(x, x) = x),所以上面的并集运算可以直接转 max\max

假设数对 (i,j)(i, j) 的权值是 ai+aja_i + a_j,那么要求的答案可以看做 max(AK)=maxi=1Kmax(Bi)\max(A_K) = \max_{i = 1}^K \max(B_i)

因此考虑求 max(Bk)=max{ai+aj i,jk}\max(B_k) = \max\{a_i + a_j \mathop | i, j \subseteq k\}

不难发现,我们只需要维护满足 iki \subseteq kaia_i 的最大值和次大值分别作为 aia_iaja_j,就能让和取到最大值。

而最大值和次大值与和一样,可以方便地合并。这题做完了。

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2023-04-17 10:20:23 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2023-04-17 11:06:28
 */
#include <bits/stdc++.h>
inline int read() {
    int x = 0;
    bool f = true;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar())
        if (ch == '-')
            f = false;
    for (; isdigit(ch); ch = getchar())
        x = (x << 1) + (x << 3) + ch - '0';
    return f ? x : (~(x - 1));
}
inline bool gmx(int &a, int b) {
    return b > a ? a = b, true : false;
}

const int maxn = 19;
std :: vector <int> f[1 << maxn];

int main() {
    int n = read();
    for (int i = 0; i < (1 << n); ++i)
        f[i].push_back(read());
    
    for (int j = 0; j < n; ++j) {
        for (int i = 0; i < (1 << n); ++i) {
            if (i & (1 << j)) {
                int lst = i ^ (1 << j);
                for (int x : f[lst])
                    f[i].push_back(x);
                std :: sort(f[i].begin(), f[i].end(), std :: greater <int> ());
                while (f[i].size() > 2)
                    f[i].pop_back();
            }
        }
    }

    int ans = 0;
    for (int K = 1; K < (1 << n); ++K) {
        gmx(ans, f[K][0] + f[K][1]);
        printf("%d\n", ans);
    }
    return 0;
}
posted @   dbxxx  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示