与位运算 进制相关
&与运算
t=k>>n&1 表示获得k二进制n位上的数字
|或运算 可以(0 1)位最大值 如果是|0的话就不变 强制给最后一位赋值为1
n|1-1变成最小的偶数 n|1变成最小的奇数
异或运算
题意只有01两种情况 某个变量a如果只有1,0两个值那么如果a^=1就可以做到 1变0,0变1
链接:https://ac.nowcoder.com/acm/contest/23479/K
来源:牛客网
小红拿到了一个正整数 x 。她想构造一个正整数 y,满足以下性质:
- y 是 x 的倍数,且 x 和 y 不能相等。
- x 在二进制表示下(为一个01串)是 y 的二进制表示的一个子串。且 x 和 y 的二进制表示的1的个数不能相同。
- y 必须为不超过 10^{19}10
19
的正整数。
举个例子:
若 x=5x=5 :
那么构造的 yy 不能是5,因为这样 yy 和 xx 相等,所以非法。
也不能是 6,因为这样 yy 不是 xx 的倍数,所以非法。
也不能是 10 ,因为这样 yy 的二进制表示是 1010、xx 的二进制表示是101,虽然 y 是 x 的倍数且 xx 的二进制是 y 的一个子串,但它们的 '1' 的个数相同,所以非法。
最简单的构造 保证 是倍数 是二进制字串 比x大
左移 左移后加上x即可 在x的基础上左移
#include <iostream>
using namespace std;
typedef long long ll;
int getLen(ll x){//获得位数
int ans = 0;
while(x > 0){
x >>= 1;
ans++;
}
return ans;
}
int main(){
ll x;
cin >> x;
ll y = x << getLen(x);
y += x;
cout << y;
return 0;
}
https://www.acwing.com/problem/content/2060/
给出二进制 三进制 数字a 在二进制和三进制表示下 只有一位不同 求a
二进制 三进制枚举每一位 在求交集
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;
const int N = 65;
int get(string a,int b){//将b进制转化为10进制
int res=0;
for( auto c:a){
res=res*b+c-'0' ;
}
return res;
}
int main()
{ string a,b;cin>>a>>b;
unordered_set<int>s;
for (auto &c:a ){//'0'ascll码48 '1'的ascll是49 两者之间转换 异或1就可以
c^=1;
s.insert(get(a ,2));
c^=1;//还原回来
}
for (auto &c : b ){
auto t=c;//记录字母 用于之后还原回来
for (int j = 0;j < 3; j ++ ){
if( t!='0'+j ){//暴力 0-2
c='0'+j;
int x=get( b,3);
if(s.count(x)){
cout << x;
return 0;
}
}
}
c=t;
}
return 0;
}
闪烁https://www.acwing.com/problem/content/1962/
n盏灯每栈灯如果上一时刻前一盏灯是1那么这盏灯就会切换状态
因为n盏灯只有开和关两种状态 所以共有 1<<n 种状态
所以 状态压缩->将状态存二进制数 然后用10进制来存
1^15那么秒次操作 就需要进行位运算
剩下的就是位运算
t=k>>n&1 表示获得k二进制n位上的数字
|或运算 可以(0 1)位最大值 如果是|0的话就不变 强制给最后一位赋值为1
n|1-1变成最小的偶数 n|1变成最小的奇数
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1 << 16;//总的状态大小,以这个状态开空间不会爆
int n;
LL m;
int p[N];//p的值表示这个状态是第几部走到的
int update(int state)//更新状态
{
int res = 0;
for (int i = 0; i < n; i ++ )
{
int j = (i - 1 + n) % n;//取得二进制第i位下左边一位
int x = state >> i & 1, y = state >> j & 1;//取得最后一位
res |= (x ^ y) << i;//对于新的第i位等于两者的异或
}
return res;
}
void print(int state)
{
for (int i = 0; i < n; i ++ )
cout << (state >> i & 1) << endl;//按位输出每个状态
}
int main()
{
cin >> n >> m;
int state = 0;//用int的state 表示总的状态
for (int i = 0; i < n; i ++ )
{
int x;
cin >> x;
state |= x << i;//每个等的初始状态 x 加到总状态state上
}
memset(p, -1, sizeof p);//初始话
p[state] = 0;
for (int i = 1;; i ++ )
{
state = update(state);//更新一次状态
if (i == m)//如果还没进入了循环就到达了最终的状态就打印
{
print(state);
break;
}
else if (p[state] == -1) p[state] = i;//如果这个状态是第一次到达的就给这个状态记录上是第几个状态到达的
else
{
int len = i - p[state];//环的长度等于上一次到达这里和本次到达的差
int r = (m - i) % len;//还需要走多少次 这里i也可以是p【state】
while (r -- ) state = update(state);//再走这么多步就可以了
print(state);
break;
}
}
return 0;
}