首先,要了解位运算
算数位运算:
1、与(&):
对于指定的两个数A=60(0011 1100)
B=13(0000 1101)
执行一下操作 A&B=12(0000 1100)
就是对二进制每一位进行了一次与操作,同为1,结果为1,否则为0
2、或(|):
对于指定的两个数A=60(0011 1100)
B=13(0000 1101)
执行一下操作 A|B=61(0011 1101)
就是对二进制每一位进行了一次或操作,同为0,结果为0,否则为1
3、非 按位取反(~):
对于指定的一个数A=60(0011 1100)
执行以下操作 ~A=195(1100 0011)
就是对二进制每一位进行了一次取反操作,若二进制数位0,则变成1,否
则变成0
4、异或运算
异或,英文为exclusive OR,缩写成xor
异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:
a⊕b = (¬a ∧ b) ∨ (a ∧¬b)
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位。
对于异或一个非常重要的性质,对于一个值异或同一个值两次,则结果还是原值。
在c/c++中异或用^符号表示;
例如:
对于指定的两个数 A=60(0011 1100)
B=13(0000 1101)
执行一下操作 A^B=49(0011 0001)
就是对二进制每一位进行了一次异或操作,即非进位加法。
二进制移位操作符:
移位操作有两种左移与右移:
1、左移<<
例如:A=5(0101)
如果向左移动一位即A<<1结果为1010,十进制的10。二进制中的左移就是乘二操作,在c/c++中左移运算速度比乘二速度要快。
2、右移>>
例如:A=5(0101)
如果向右移动一位即A>>1结果为0010,十进制的2。二进制中的左移就是除二操作(舍去小数)。
二进制枚举
二进制枚举利用的是二进制下n位长度的数有2n个,一个有n个元素的集合子集个数也为2n个,所以可以利用二进制的1,0和集合中的元素联系起来他可以实现组合也可以实现容斥
对一个二进制来说1代表取这个元素,0代表不取这个元素,1和0所在的位置代表元素的位置,这样的思想在有时候给题目有了很大的方便举个例子如集合{a,b,c,d,e}
当二进制00000就代表什么都不取, 10000代表取a,01000代表取b,11000代 表取a,b如此
所以我们需要枚举的数量就是00000到11111,也就是0到1<<n位,<<代表左移操作
teacher Li
本题应考虑二进制异或,即对字符串的每一位进行异或,因为每个字符对应属于自己的ASICC码值,且根据题意,只有一位同学没来,也就说明,所有的字符串中,除了那个没来的同学,其他名字都出现了两遍,那样的话,从头到尾进行异或,最终得到的结果就会是没来的那位同学的名字
对于异或一个非常重要的性质,对于一个值异或同一个值两次,则结果还是原值。
一个数与0进行异或,其结果不变!!!
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,i,j,k;
char x[30],y[30];
k=1;
while(cin>>n>>x)
{
for(i=1;i<=2*n-2;i++)
{
cin>>y;
for(j=0;j<max(strlen(x),strlen(y));j++)//这里要取长的字符串长度//
{
x[j]=x[j]^y[j];
}
}
printf("Scenario #%d\n",k++);
printf("%s\n\n",x);
}
return 0;
}
Find different
本题由于n非常大,无法用数组装,因此直接输入每一个数,然后直接进行异或,想法与上一题相同!!!
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long n;
int ans,i;
while(scanf("%lld",&n)!=EOF)
{
ans=0;
for(long long j=0;j<n;j++)
{
scanf("%d",&i);
ans=ans^i;
}
printf("%d\n",ans);
}
return 0;
}
和为K–二进制枚举
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,flag,x[25];
long long k,sum;
while(cin>>n>>k)
{
flag=0;
for(int i=0;i<25;i++)
{
x[i]=0;
}
for(int i=0;i<n;i++)
{
cin>>x[i];
}
for(int i=0;i<(1<<n);i++)
{
sum=0;
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
sum+=x[j];
}
}
if(k==sum)
{
flag=1;
break;//找到一个符合就退出//
}
}
if(flag==0)
{
cout<<"No"<<endl;
}
else
{
cout<<"Yes"<<endl;
}
}
return 0;
}
陈老师加油-二进制枚举
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,sum,k1,k2,T;//t是临时变量,记录每种方案的油量//
while(cin>>T)
{
sum=0;
for(int i=0;i<(1<<15);i++)
{
k1=k2=0;
t=T;
for(int j=0;j<15;j++)
{
if(i&(1<<j))
{
t*=2;
k1++;
}
else
{
t-=1;
k2++;
if(t<=0)//油不能不大于0//
break;
}
}
if(k1==5&&k2==10&&t==0)
{
sum++;
}
}
cout<<sum<<endl;
}
return 0;
}
纸牌游戏-二进制-搜索
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,p;
int x[25],sum,count;
while(cin>>n>>p)
{
for(int i=0;i<n;i++)
{
x[i]=0;
}
for(int i=0;i<n;i++)
cin>>x[i];
count=0;
for(int i=0;i<(1<<n);i++)
{
sum=0;
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
sum+=x[j];
}
}
if(sum==p)
count++;
}
cout<<count<<endl;
}
return 0;
}
权利指数
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n,sum,add;//sum是总票数,add是同意的票数//
int x[25],y[25];//x是票数数组,y是权利指数数组//
while(cin>>t)
{
for(int i=0;i<t;i++)
{
sum=0;
cin>>n;
for(int i=0;i<n;i++)
x[i]=y[i]=0;
for(int i=0;i<n;i++)
{
cin>>x[i];
sum+=x[i];
}
for(int i=0;i<(1<<n);i++)
{
add=0;
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
add+=x[j];
}
}
if(add>(sum/2))
{
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
add-=x[j];
if(add<=(sum/2))//无论该团体是不是关键小团体,都得把剪掉的数再加回来//
{
y[j]++;
add+=x[j];
}
else
{
add+=x[j];
}
}
}
}
}
for(int i=0;i<n-1;i++)
cout<<y[i]<<" ";
cout<<y[n-1]<<endl;
}
}
return 0;
}
趣味解题
本题的想法是先把每道题的ac,wa的概率都算出来,分别装到两个数组里,然后二进制枚举进行遍历,对于每种方案的概率是ac题的概率之积乘以wa题的概率之积,然后把所有ac题数符合题意的方案的概率相加
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n,x,k;
double a[15],b[15],c[15],ac[15],wa[15],ans,ans1;
while(scanf("%d",&t)!=EOF)
{
for(int i=0;i<t;i++)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%lf",&a[i]);
}
for(int i=0;i<n;i++)
{
scanf("%lf",&b[i]);
}
for(int i=0;i<n;i++)
{
scanf("%lf",&c[i]);
}
scanf("%d",&x);
for(int i=0;i<n;i++)
{
wa[i]=(1.0-a[i])*(1.0-b[i])*(1.0-c[i]);
ac[i]=1.0-wa[i];
}
ans=0;
for(int i=0;i<(1<<n);i++)
{
k=0;
ans1=1.0;
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
ans1*=ac[j];
k++;
}
else
{
ans1*=wa[j];
}
}
if(k==x)
{
ans+=ans1;
}
}
printf("%.4lf\n",ans);
}
}
return 0;
}
四糸乃买花-二进制枚举
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,k,count;
long long a[25],w,w1;//w1记录每种方案剩下的钱//
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
cin>>w;
count=0;
for(int i=0;i<(1<<n);i++)
{
k=0;
w1=w;
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
w1-=a[j];
k++;
}
}
if(k%4==0&&w1%4==0&&k>0&&k<n&&w1>=0)//k不能为0,也不能为n,而且剩下的钱应为正或者正好为0,且k,w1都要是4的倍数//
{
count++;
}
}
cout<<count<<endl;
return 0;
}