CF2035C

CF2035C

一道很关于位运算的很好的构造题,纠正了我先前对位运算的一些误解。

分析

确定一个 permutation(n) ,使得:

k=0 (初始),从 1nk 依次进行操作。如果 k 是奇数 k&ai ,否则 k|ai

之前认为,与和或结合的结合的位运算是具有结合律的,也就是可以先把与的部分算出来,再或起来。

但实际上这是错误的,只能从左到右依次计算,checker如下 :

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N];
bool check(int n)
{
int k=0;
for(int i=1;i<=n;++i)
{
if(i&1)k&=a[i];
else k|=a[i];
}
int cmp=0;
for(int i=2;i<=n-1;i+=2)
cmp|=a[i]&a[i+1];
return k==cmp;
}
int main()
{
int n=9;
for(int i=1;i<=n;++i)a[i]=i;
int T=100;
do
{
cout<<check(n)<<endl;
}while(next_permutation(a+1,a+n+1));
return 0;
}

但是很容易可以想到一个贪心的做法,发现样例里面:

所有奇数 n 能得到的最大数就是他本身

所有偶数 n 能得到的最大数是把它本身的 0 全部变成 1 后的结果

所以不难想到分 n 的奇偶性讨论。

Case odd

如果 n 为奇数,那么最后一位一定是 & ,最后的答案就一定小于等于我们放在最后一位的数。

所以贪心地把最大的 n 放在最末尾,尝试让前面的 n1 个运算凑出 n 这个数值。

可以观察发现 n1 这个偶数实际上和 n 只差了最后一位的 1 ,那么最后几位只需要是 :
1,n2,n1,n

Case even

这时候最后一位是 | ,那么为了补齐所有的 0 ,我们尝试在前面 n1 个凑出除了最高位,其他都是 1 的数。

这一点只需要顾名思义地来做就可以了,然后要注意到 当 n2 的若干次幂的时候,我们在前 n1 个要凑出的数就是 n1

Code

posted @   Hanggoash  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
动态线条
动态线条end
点击右上角即可分享
微信分享提示