#include<bits/stdc++.h>
using namespace std;intmain(){int n, k;scanf("%d%d",&n,&k);//约定:整数n的二进制数,由低位 -> 高位依次为:0号位、1号位、2号位... //取出k号位上的数字 printf("%d\n",(n >> k)&1);//取出后k位:和k位1做按位与运算printf("%d\n", n &((1<< k)-1));//将k号位取反:k号位和1异或运算;其它位和0异或运算printf("%d\n", n ^(1<< k));//将k号位赋值为1:k号位和1或运算;其它位和0或运算printf("%d\n", n |(1<< k));//将k号位赋值为0:k号位和0与运算;其它位和1与运算printf("%d\n", n &(~(1<< k)));//统计非负整数n的二进制中1的个数int cnt =0;for(int i =0; i <30; i ++)if(n >> i &1)
cnt ++;printf("%d\n", cnt);//统计非负整数n的二进制中1的个数
cnt =0;while(n){
cnt ++;
n &= n -1;}printf("%d\n", cnt);return0;}
a^b
#include<bits/stdc++.h>#defineLLlonglong
using namespace std;intmain(){
LL a, b, p;scanf("%lld%lld%lld",&a,&b,&p);
LL res =1% p;//如果b为0, 则结果等于1%p//19: 0b10011//a^19 = (a^16) * (a^2) * (a^1)while(b){if(b &1) res = res * a % p;
a = a * a % p;
b >>=1;}printf("%lld\n", res);return0;}
64位整数乘法
位运算
#include<bits/stdc++.h>#defineLLlonglong
using namespace std;intmain(){
LL a, b, p, res =0;scanf("%lld%lld%lld",&a,&b,&p);//19: 0b10011//a*19 = (a*16) + (a*2) + (a*1)while(b){if(b &1) res =(res + a)% p;
a = a *2% p;
b >>=1;}printf("%lld\n", res);return0;}
扩展:用long double
#include<bits/stdc++.h>#defineLLlonglong
using namespace std;intmain(){
LL a, b, p;scanf("%lld%lld%lld",&a,&b,&p);//a*b % p = (a%p) * (b%p) % p
a %= p, b %= p;// a*b % p = a*b - 下取整(a*b/p) * p// a*b/p 的整数部分小于10^18,而long double能提供18~19位有效数字,可以满足//赋值给整型变量,相当于对 a*b/p 取整
LL c =(longdouble) a * b / p;//虽然a*b和c*p都可能很大,但是它们的差的范围是[0,p),也就是小于10^18,//虽然a*b和c*p的高位溢出,但是低18位的差被正确保留在long long变量里
LL res = a * b - c * p;if(res <0) res += p;elseif(res >= p) res -= p;printf("%lld\n", res);return0;}
Raising Modulo Numbers
#include<bits/stdc++.h>#defineLLlonglong
using namespace std;intmain(){int z;
cin >> z;while(z --){int m, h, ans =0, res;
cin >> m >> h;for(int i =1; i <= h; i ++){int a, b;
cin >> a >> b;
res =1% m;while(b){if(b &1) res =(LL)res * a % m;
a =(LL) a * a % m;
b >>=1;}
ans =(ans + res)% m;}
cout << ans << endl;}return0;}
起床困难综合症
暴力30分
#include<bits/stdc++.h>
using namespace std;constint N =1e5+10;int n, m, maxx;
string s[N];int a[N];intmain(){
cin >> n >> m;for(int i =1; i <= n; i ++) cin >> s[i]>> a[i];for(int i =0; i <= m; i ++){//枚举初始攻击力0,1,2,...mint t = i;for(int j =1; j <= n; j ++){if(s[j]=="AND") t &= a[j];if(s[j]=="OR") t |= a[j];if(s[j]=="XOR") t ^= a[j];}
maxx =max(maxx, t);}
cout << maxx << endl;return0;}
位运算100分
#include<bits/stdc++.h>
using namespace std;constint N =1e5+10;int n, m;
string s[N];int a[N];intmain(){
cin >> n >> m;for(int i =1; i <= n; i ++) cin >> s[i]>> a[i];//用变量num表示初始攻击力,一开始赋值为0,也就是二进制的每一位都是0 int num =0;//m的范围是[0,1e9],因为2^30 > 1e9,所以用30位二进制数就够了for(int i =0; i <=29; i ++){//num必须小于等于m, 且每一位经过n次位运算之后要尽可能大://如果num的第i位是1,且运算后第i位还是1,则将它赋值为1有助于得到更大的结果 //如果num的第i位是1,但运算后第i位变成0,则没必要将它赋值为1//如果num的第i位是0,且运算后第i位变成1,则保留初始值0//如果num的第i位是0,且运算后第i位变成0,则还是保留初始值0//综上,只有当初始为1,且运算后还是1,才有必要将这一位赋值为1int t =1;for(int j =1; j <= n; j ++){if(s[j]=="AND") t &=(a[j]>> i &1);//和第i位运算 if(s[j]=="OR") t |=(a[j]>> i &1);//和第i位运算if(s[j]=="XOR") t ^=(a[j]>> i &1);//和第i位运算}if(t ==1) num |=(1<< i);//将第i位赋值为1 }//num应该小于等于mfor(int i =29; i >=0; i --){if(num <= m)break;
num &=(~(1<< i));//如果num太大,则将高位赋值为0 }//这时候的num就是符合题意的初始攻击力,经过n次操作后就得到最终的伤害值int t = num;for(int i =1; i <= n; i ++){if(s[i]=="AND") t &= a[i];if(s[i]=="OR") t |= a[i];if(s[i]=="XOR") t ^= a[i];}
cout << t << endl;return0;}
寻找独一无二的数
异或运算的性质有: – a ^ a = 0 – a ^ 0 = a – 交换律: a ^ b = b ^ a – 结合律: (a ^ b) ^ c = a ^ (b ^ c) – 自反:a ^ b ^ a = b
#include<iostream>#include<cstdio>
using namespace std;intmain(){int n, x, ans =0;scanf("%d",&n);for(int i =1; i <= n; i ++){scanf("%d",&x);
ans ^= x;}printf("%d", ans);return0;}
起床困难综合症暴力30分#include <bits/stdc++.h>using namespace std;const int N = 1e5 + 10;int n, m, maxx;string s[N];int a[N];int main() { cin >> n >> m; for (int i = 1; i <= n; i ++) cin >> s[i] >> a[i]; for (int i =