CF#618div2 C题

CF#618div2 C. Anu Has a Function

这又是一道关于逻辑运算的题目,这种奇奇怪怪的莫名转换实在是让我有点懵啊=-=估计是数字逻辑没有学好的原因
传送门

题目大概意思就是给了一个函数定义,然后给你一个序列,问怎么排列才可以使得最后的值最大。

当然暴力求解当然会T,让我们对函数的定义做一点变换
函数是这样定义的:
f : f(x, y) = (x | y) − y;就是x和y的或起来的值,再减去y,求得式子只是叠加起来的。
我们看到(x | y) - y这个东西:x | y可以表示成: x + y - x & y;
然后 (x | y) − y这玩意就可以表示成x - x & y,进而就是x & (1 - y)
最后就是x & (~y)
要求的式子就是a1 & (~a2) & (~a3) & (~a4)…
我们要让这个式子最大,就来思考思考。
唯一一个没有取反的就是a1,那么一个数越大,取反的结果越小,我们按照二进制的数来看,我们就不能让越大的数取反,所以越大的数应该是a1,相反,越小的数取反是不是就越大呢?嘻嘻,答案是肯定的,那么我们后面的a2,a3,a4…怎么取都不需要管,因为反正都一样的操作,都要取反,都要相与,结果都一样,现在最关键的是选出一个合适的a1,让式子的值最大。我们考虑二进制下,最高位的1。我们要选出尽可能最高位的1让这个数来当a1,这个最高位的1必须是唯一的,不能存在多个最高位的1,因为只有a1不用取反呀,保留了a1的最高位的1,如果存在多个,那么其他的将会被取反,都变为了0,最后结果再相与,那么最后把最高位的1变为了0,这不就白费功夫了嘛,所以我们应该找出唯一的最高位的1.
找出唯一的最高位的1的方法有很多啦。
比如:
假设当前操作的数字为x,我们将x右移j位,然后跟1相与,不为0的话,记录下标,然后把序列判断完,判断是否为唯一的最高位1.

上代码啦~~

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
 
int n;
int a[N];
 
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}
	
	int ans;
	for (int i = 30; i >= 0; i--)
	{
		int flag = 0;
		for(int j = 0; j < n; j++)
		{
			if ((a[j] >> i) & 1)
			{
				flag++;
				ans = j;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
	cout << a[ans] << " ";
	for (int i = 0; i < n; i++)
	{
		if (i != ans)
		{
			cout << a[i] << " ";
		}
	}
	cout << endl;
	return 0;
}

我们下次见~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

娃娃酱斯密酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值