CF1635A Min Or Sum

发个严谨点的证明罢。

引理

$$ x|y≤x+y $$ 先搞个真值表出来:

$a$ $b$ $a\vert b$ $a+b$
1 1 1 2
1 0 1 1
0 1 1 1
0 0 0 0

可以看出,对于任意二进制位 $a,b$,$a|b≤a+b$。

设 $x$ 的第 $k$ 个二进制位为 $x_k$,则对于任意 $x,y$,$x_k|y_k≤x_k+y_k$。

(如果 $x,y$ 位数不同,则在位数少的数前面补 $0$)

我们有:$$ x+y=\sum\limits2^k(x_k+y_k),x|y=\sum\limits2^k(x_k|y_k) $$ 作差法比较大小:$$ \begin{aligned} (x+y)-(x|y)&=\sum\limits2^k(x_k+y_k)-\sum\limits2^k(x_k|y_k)\\ &=\sum\limits2^k[(x_k+y_k)-(x_k|y_k)]≥0 \end{aligned} $$ 所以 $x|y≤x+y$。

思路

因为 $x|0=x$,所以可以把 $a_i,a_j$ 变成 $a_i|a_j,0$。

($a_i|a_j=(a_i|a_j)|0$,符合题目要求)

这样做之后,原来的和 $a_i+a_j$ 就变成了 $a_i|a_j$,

根据引理可以知道 $a_i|a_j≤a_i+a_j$,比原来更优。

于是就可以对 $a_1$ 和 $a_{i∈[2,n]}$ 都执行一遍这个操作,

原数列就变成 $a_1|a_2|a_3|...|a_n,0,0,0...$,不含有加法,是最小值。

代码

#include <cstdio>
int T, n, s, t;
int main()
{
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);s = 0;
        while(n--) scanf("%d", &t), s |= t;
        printf("%d\n", s);
    }
    return 0;
}
posted @ 2022-03-25 17:02  Jijidawang  阅读(2)  评论(0编辑  收藏  举报  来源