codeforce1368D. AND, OR and square sum

問題は予想よりも簡単です

给一个数组,里面n个数 a i a_i 。You are allowed to perform the following operation: choose two distinct indices 1≤i,j≤n. If before the operation ai=x, aj=y, then after the operation ai=x AND y, aj=x OR y,
然后求 a i \sum a_i 最大值


x 1 < x 2 x_1<x_2 根据AND 和 OR 操作的特点,有
y 1 = x 1 x 2 = x 2 + α y 2 = x 2 & x 2 = x 1 α α = (   x 2 ) & x 1 y_1 = x_1 | x_2 = x_2+\alpha \\ y_2 = x_2 \& x_2 =x_1-\alpha \\ \alpha = (~x_2) \& x_1 \\

实例演示一下:
等我数位板到了就补个图

所以想要操作后和变大只需要
y 1 2 + y 2 2 x 1 2 x 2 2 > 0 y_1^2 + y_2^2 - x_1^2 - x_2^2 >0
带入可得
2 α ( α + x 2 x 1 ) > 0 2\alpha ( \alpha +x_2-x_1) > 0
所以只要满足这个条件那么就执行操作,直到没有满足条件的这一对数。
但是一个一个试太多了,这样复杂度就是O(n2)了,不妥,还得再研究研究
现在我们重新审视一下这个操作在二进制层面的变化:将 x 1 x_1 中为1而 x 2 x_2 为0的位 转移到 x 2 x_2 上 并将 x 1 x_1 的1抹去,直白一点,就是 x 1 x_1 把自己分了,分给了很多个不同的 x 2 x_2 。那么,这个题实际只需要统计二进制下不同位上1的个数就可以了,然后去构造尽可能大的数。
神奇的复杂度诞生了.jpg

#pragma GCC diagnostic error "-std=c++11"
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return

#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;

template<class T> void _deb(const char *name,T val){
    cout<<name<<val<<endl;
}

const int maxn=2e5+5;

int n;
int digNum[24];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    cin>>n;
    rep(i,0,n){
        int tmp;
        cin>>tmp;
        int pos=0;
        while(tmp){
            digNum[pos]+=tmp%2;
            tmp/=2;
            pos++;
        }
    }


    ll ans=0;
    bool add=true;
    while(add){
        int minNum=INT_MAX;
        rep(i,0,20){
            if(digNum[i]>0 && minNum>digNum[i])
                minNum=digNum[i];
        }
        if(minNum==INT_MAX){
            add=false;
            continue;
        }
        int num=0;
        rep(i,0,20){
            num+=(1<<i)*(digNum[i]>0);
            digNum[i]-=minNum;
        }
        ans+=1LL*num*num*minNum;
    }
    cout<<ans<<endl;


    re 0;
}

猜你喜欢

转载自blog.csdn.net/white_156/article/details/106971461
今日推荐