zoukankan      html  css  js  c++  java
  • 【HNOI2016模拟4.14】B

    这题比较容易能想到的
    由于它每次更新都是将a,b改变为a|b,a&b
    我们不妨证明一下:

    (a|b)2+(a&b)2>a2+b2

    证明如下:
    设x=a&b
    (a|b)2+(a&b)2=(a+b-x)2+x2^
    反正法:
    假设证明不成立

    (a+b-x)2+x2<a2+b2
    (a+b-x)2-b2<a2-x2
    (a-x)(a+2*b-x)<(a-x)(a+x)

    由于x<=b(易得)
    所以2*b-x>=x
    得证
    所以我们就可以清楚地知道:

    要尽可能地用到那个更新

    (也就是说要将其中一个数尽可能搞大)

    套套样例看看:
    5
    1 2 3 4 5
    转成二进制:
    1
    10
    11
    100
    101
    110
    这样的话,我们就要把它变为111,111,1(二进制)
    也就是72+72+12=99
    在这其中,我们发现:

    它二进制上的每一个位置的个数和是不变的。

    这样我们就可以用个桶来做了。
    上标:

    #include<cstdio>
    #define ll long long
    using namespace std;
    int n,a[100010],t,t1,tot[21];
    ll ans;
    
    inline int read()
    {
    	int x=0; char c=getchar();
    	while (c<'0' || c>'9') c=getchar();
    	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x;
    }
    
    int main()
    {
    	n=read();
    	for (int i=1,x;i<=n;i++)
    	{
    		x=read();
    		for (int j=1;j<=20;j++)
    			if (x & (1<<j-1)) tot[j]++;
    	}
    	for (int i=1,x;i<=n;i++)
    	{
    		x=0;
    		for (int j=1;j<=20;j++)
    			if (tot[j]) tot[j]--,x+=(1<<j-1);
    		if (!x) break;
    		ans+=(ll)x*x;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    转载需注明出处。
  • 相关阅读:
    smbmnt
    smbd
    smbcontrol
    smbclient
    smb.conf
    sleep
    size
    oracle-rman-1
    cURL 学习笔记与总结(5)用 cURL 访问 HTTPS 资源
    Java实现 LeetCode 90 子集 II(二)
  • 原文地址:https://www.cnblogs.com/jz929/p/11817685.html
Copyright © 2011-2022 走看看