予鈴

アウトプットとメモ書きの中間みたいな記事がたくさん出ます。

CF - D. AND, OR and square sum

Problem

You are given a collection of  N non-negative integers.
You can perform following operations:
choose two distinct indices  1 \leq i < j \leq N. If before the operation  a_i  = x, a_j = y, then after the operation  a_i  = x \,AND\, y, a_j = x \,OR\, y .
Maximize  \sum_{1}^{N}{a_i^2}

Solution

英語書くの疲れたので、日本語でやります。
・ある一つの操作について考える。
一般性を失わず、 a_i = x \leq  a_j = y とする。
 z = x \,AND\, y,w = x \,OR\, y とすると,  x + y \leq w + z , y \leq w.
 d  = w - yとすると、一度の操作で w^2 + z^2 - x^2 - y^2  = 2d(d + y - x)だけ答えを増加させる事ができる。


・以上の考察より、 d > 0となる(i,j)が存在する限りこの操作を行えば良い。
つまり、できるだけ大きい数字のbitを1に変えていけばよい事がわかる。

 a_j > a_iであり、 a_j n bitが0,a_in bitが1の場合を考える。
操作を行うと、 a_j n bitが1,a_in bitが0になる。この操作を繰り返して、できるだけbitを1にすれば良い。
あとはbitごとに1が立っている数を数えて、できるだけ大きい数を構築していけば良い。

#include<bits/stdc++.h>
using Int = int64_t;
using namespace std;
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    Int N; cin >> N;
    vector<Int> A(N);
    for(auto& e  : A) cin >> e;
    vector pos(20,0);
    for(auto e : A){
        for(int bit = 0; bit < pos.size(); ++bit)
            if(e & (1 << bit)) pos[bit]++;
    }
    vector ans(N,0LL);
    for(auto& e : ans){
        for(int bit = 0; bit < pos.size(); ++bit){
            if(pos[bit] > 0 ){
                e += (1LL << bit);
                pos[bit]--;
            }
        }
    }
    cout << accumulate(ans.begin(),ans.end(),0LL,
    [](auto res,auto e){
        return res += e * e;
    })
    << endl;
}