1. 与或非
2. 异或
3. 二进制枚举&&二进制移位符
**|以下内容均在二进制下操作|**
符号 :&
性质 :每一位比较,相同为1,不同为0 //只取相同位次的相同数
例:
A=60(11 1100)
B=13(00 1101) //如果没有没有就补0,让他们位次对上
A&B =(00 1100)=12 //除了1 1才是1,其他都是0
符号:|
性质:每一位比较,相同为0,不同为1 //对照着 与 来理解
例:
A= 60(11 1100)
B= 13(00 1101)
A|B =(11 0001)=61 //注意是相同的1,0和0也是相同的,但结果是0,0和1结果是1
符号:~
性质:取相反的数
例:
A= 60(11 1100)//我对不齐,有笔就笔划笔划就清楚多了
~A=195 (00 0011) //对着取就行了
//看到这,单个知识没啥用,组合起来用处就大了。下面有用
符号:^ //很重要
性质:上图
//个人理解:相同为0,不同为一(注意和上面的 与 或 区别开)
例:
A=60(11 1100)
B=13(00 1101)
A^B=(11 0001)=49 //相同都取0(无论是 1 相同,还是 0 相同),不同取1
注 ”负负得正“,一个道理
异或是不进位的加法(0+0=0,1+0=1,1+1=0(应该进位,但是没有))
想深入了解的同学,附上一个知乎的回答
如何理解「异或」的含义?::排异外
—》有啥用呢?用处可大了,用来找不同
见例题 林大oj1172
**这题的意思就是找数,只出现一次的数
上码
#include //万能开头
using namespace std;
int main()
{
int n,x,ans;
while(scanf("%d",&n)!=-1)
{
ans=0;//用下面的数据
cin>>ans;//假设第一个数是 3
n=n-1;//第二个数开始
while(n--)//(这里是个数递减)
{
scanf("%d",&x);//读下一个数 2
ans=ans^x;
/*
3和2进行异或运算——> 2(010)^3(011)=1(001)
读取下一个数 7(111),7(111)^1(001)=6(110)
读取下一个数 2(010),2(010)^6(110)=4(100)
读取下一个数 1(001),1(001)^4(100)=5(101)
读取下一个数 7(111),7(111)^5(101)=2(010)
读取下一个数 3(011),3(011)^2(010)=1(001)
我们换个理解,把二进制的限制丢开(二进制很蒙人),如果两个数相同,消灭,不同,留下
(这个是终极理解,也就是目的。过程我们用二进制实现)*/
}
printf("%d\n",ans);
}
return 0;
}
/*
样例输入
7
3 2 7 2 1 7 3
样例输出
1
*/
异或 能把不同的那个找出来
Over.
*****找字符串的不同
上题
林大oj643 找名字//还是要学点英语好。。
士兵们,上码!
//理解:点名,第一份是完整名单,第二份是现场签到的名单。异或消掉相同的就知道谁没到了
#include
using namespace std;
int n,i,t,j;
string na,ne;
int main()
{
t=0;
while(scanf("%d",&n)!=-1)
{
cin>>na;
for(int i=0; i<n*2-2; i++)//第一个数已经被读走,因为有一个人没到所以要减1,共减2
{
cin>>ne;
for(j=0; j<max(na.length(),ne.length()); j++)/*c++里的max很香。
.length()的意思是这个字符串长度多少。
从大的数开始,因为其二进制位数长,如果从小的开始就会丢(大数就会被迫变小来和小数比较)
*/
na[j]=ne[j]^na[j];//因为在表里都对应了一个数字,还是回到了找数字是否相同问题
}
t++;
printf("Scenario #%d\n",t);
printf("%s\n\n",na.c_str());/*这个 .c_str()的意思是把字符串中的东西给你原封不动输出来。
我也不是很懂,好像和string配套用。反正挺香,先记住它*/
}
return 0;
/*
3
A
B
C
B
C
*/
}
————异或完了,就这么用。找不同。
需要另外学习的有 .length(),.c_str(),max()
符号: >> 右移(减) <<左移(加)
性质: 两种形式:
直接用题理解吧。
林大 oj 1205 和为k
这里开始会用到上面说过的 与
#include
using namespace std;
int n,k,i,j,a[21],sum;
int main()
{
while(cin>>n>>k)
{
for(i=0; i<n; i++)
cin>>a[i];
int f=0;//还是枚举的思想。看有几层循环
for(i=0; i<(1<<n); i++)//上面说的,用二进制循环
{
sum=0;
for(j=0; j<n; j++)
if(i&(1<<j))//这里有 与 和 移位。如果 i 和 j 相同,& 出来就是0.这样就不会重复加了
sum=sum+a[j];
/*
用 if 判断“真”、“假”分为两种,一种是数值是否为零, 另一种是表达式是否成立。
*/
if(sum==k)
{
printf("Yes\n");
f=1;
break;
}
}
if(f==0)
printf("No\n");
}
return 0;
/*
input
5 13
2 4 6 8 10
output
NO
*/
}
林大 oj 1505 陈老师加油
理解:注意别油早没了,车还能继续跑
#include
using namespace std;
int t,ans,i;
int main()
{
while(cin>>t)
{
ans=0;//还是枚举的思想。
for(i=0; i<(1<<15); i++)//它只有两层循环,加油站和路口是一个性质。
{
int lu=0,jia=0,now=t;//第一个循环给数
for(int j=0; j<15; j++)//第二个循环比较
{
if(i&(1<<j))//别和自己比就行(用 与 运算排除掉)
{
lu++;now--;
if(now<=0)
break;//油都没了这必跑不了了
}
else
{
jia++;
now*=2;
}
}
if(lu==10&&jia==5&&now==0)//只有油没了,路口加油站全过才能通过
ans++;
}
printf("%d\n",ans);
}
return 0;
}
林大 oj 1518 纸牌求和
//同上面的 和为k 一个意思,但你得循环完,不提前结束
#include
using namespace std;
int a[21],p,n,i,sum,j,ans;
int main()
{
while(scanf("%d",&n)!=-1)
{
cin>>p;
for(i=0; i<n; i++)
cin>>a[i];
ans=0;
for(i=0; i<(1<<n); i++)
{
sum=0;
for(j=0; j<n; j++)
{
if(i&(1<<j))
sum=sum+a[j];
}
if(sum==p)
ans++;
}
printf("%d\n",ans);
}
return 0;
}
不多说,有请(看)下一位(道)选手(题),开始你的表演(做题)
林大 oj 1641 权利指数
//这题比较麻烦些,暴力它
//开个一样的数组记它是不是在关键团队里面
#include
using namespace std;
int n,t,i,j,sum,tmp,a[21],ans[21],flag[21];//flag就是判断
int main()
{
while(scanf("%d",&t)!=-1)
{
while(t--)
{
cin>>n;
sum=0;
for(i=0; i<n; i++)
{
cin>>a[i];sum+=a[i];//求总票数sum。*=这一类的符号还是好用的。
}
sum=sum/2;//先除了,懒
memset(ans,0,sizeof(ans));//好习惯,归0;C++的好处,不用for循环归0
for(i=0; i<(1<<n); i++)
{
tmp=0;
memset(flag,0,sizeof(flag));
for(j=0; j<n; j++)
{
if(i&(1<<j))
{
tmp=tmp+a[j];
flag[j]=1;//如果这个数在里面,记下它
}
}
if(tmp<=sum)//还有一种思路,从已经超过的组里面找关键票
{
for(j=0; j<n; j++)
{
if(tmp+a[j]>sum&&flag[j]==0)ans[j]++;//两个条件都得满足:1.是关键票 2.不在组里面
}
}
}
for(i=0; i<n-1; i++)printf("%d ",ans[i]);
printf("%d\n",ans[n-1]);//注意格式,中间空格尾数换行
}
}
return 0;
}
林大 oj 1285 趣味解题
//涨知识,错了很心疼
//这题要把概率算清楚
#include
using namespace std;
double a[15],c[15],b[15],ac[15],wa[15],ans,p;
int t,x,n,i,j,tex;
int main()
{
cin>>t;
for(int z=0; z<t; z++)
{
cin>>n;
for(i=0; i<n; i++)
cin>>a[i];
for(i=0; i<n; i++)
cin>>b[i];
for(i=0; i<n; i++)
cin>>c[i];
cin>>x;
ans=0;
for(i=0; i<(1<<n); i++)//枚举,两个循环找完
{
p=1; tex=0;//得从1开始,p要是1,才能让概率出现
for(j=0; j<n; j++)
{
wa[j]=(1-a[j])*(1-b[j])*(1-c[j]);//要是想先算ac再算wa,它就是不行(精度问题?)
ac[j]=1-wa[j];
if(i&(1<<j))
{
p=p*ac[j];tex++;
}
else
p=p*wa[j];
}
if(tex==x)ans=ans+p;
}
printf("%.4lf\n",ans);
}
return 0;
}
总结
1.二进制枚举找数,还是枚举的思想。但引入了二进制,避免自己找自己
2.异或运算,解决找不同的问题很方便(用二进制找)
3.与 (别找自己),或(找其他),
杂
1.基本运算符和=组合运用
2.max()
3. .ength()
4. .c_str()
大概是这些了,不懂还是多百度多问,压榨大佬也是不错的选择,让他给你检查代码。