二进制枚举(自用)
原理讲解
利用二进制只有0与1来表示成立与否,枚举出所有情况
二进制知识点
for(int i=0;i<(1<<n);i++)//n个选项
for(int j=0;j<n;j++)//从第一个选项开始遍历
if(i$(1<<j)) count++;//若同为1,便加加
陈老师加油-二进制枚举
典型的二进制枚举
代码实现如下
#include <bits/stdc++.h>
using namespace std;
int t,x,y,i,j,n=0,b;
int main()
{
scanf("%d",&b);
for(i=0; i<(1<<15); i++)//路口与加油站一共15个,也就是15个01选项
{ x=0;
y=0;
t=b;
for(j=0; j<15; j++)
{
if(i&(1<<j))
{
t*=2;
x++;
}
else
{
t-=1;
y++;
}
if(t<=0) break;//燃油耗尽即break
}
if(t==0&&x==5&&y==10)//满足题目条件
n++;
}
printf("%d\n",n);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,a[22],b[22]= {0},sum,sum1,sum2,t;
cin>>t;
for(int k=0;k<t;k++)
{ cin>>n;
sum=0;
memset(b,0,sizeof(b));//重置b数组,以免输出错误
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sum=sum/2;
for(int i=0; i<(1<<n); i++)
{
sum1=0;
for(int j=0; j<n; j++)//遍历出所有组合
{
if(i&(1<<j)) sum1+=a[j];
}
if(sum1>sum)//如大于半数
{
for(int j=0; j<n; j++)
{ sum2=sum1;
if(i&(1<<j))
{
sum2-=a[j];
if(sum2<=sum)//关键处理,如减去后小于半数,即为关键者一次
b[j]++;//进行计数(故前面需要清0)
}
}
}
}
for(int i=0;i<n;i++)
{
if(i!=n-1) printf("%d ",b[i]);
else printf("%d\n",b[i]);
}
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,t,cot,x;
double ans,a[14],b[14],c[14],p,ac[14],wa[14];
cin>>t;
while(t--)
{ ans=0;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
cin>>b[i];
for(int i=0;i<n;i++)
cin>>c[i];
cin>>x;
for(int i=0;i<(1<<n);i++)
{
p=1;cot=0;//概率,计数清0
for(int j=0;j<n;j++)
{
wa[j]=((1-a[j])*(1-b[j])*(1-c[j]));//算出未ac概率
ac[j]=1-wa[j];//ac概率
if(i&(1<<j))
{
p=p*ac[j]; cot++;//如遍历至此题ac则乘上ac概率,否则*wa概率
}
else p=p*wa[j];
}
if(cot==x)
ans+=p;
}
printf("%.4lf\n",ans);
}
}
Find different
此题为二进制异或典型题
所谓异或,即为
代码实现如下
#include <bits/stdc++.h>
using namespace std;
int n,ans,a;
int main()
{
while(scanf("%d",&n)!=EOF)
{
scanf("%d",&ans);
n--;
while(n--)
{
scanf("%d",&a);
ans=ans^a;//将输入的每一个数异或,便能得到奇数次的数
}
printf("%d\n",ans);
}
return 0;
}
讲到异或此处再献上一题
n−x=n^x 这是题目中式子的变形,异或运算让我们联想到二进制,于是就用二进制来思考这道题,发现当n的k位为0时,那么x为1时,不相等,x为0时相等,当k=1时,x=0与x=1均成立,所以,只需将n转化二进制,看其有多少1,即乘以相应的2即可,代码实现如下,先是蒟蒻的版本,再是指点版
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
int main()
{
int p[35],k,m;
p[0]=1;
for(int i=1;i<31;i++)
p[i]=p[i-1]*2;//先打表,预处理出所有的情况
while(scanf("%lld",&n)!=EOF)
{ m=0;
for(int i=1;i<35;i++)
{
if(p[i]>n)
{k=i-1;
break;}//这一步处理,即可得到输入n的二进制位数
}
for(int i=0;i<=k;i++)
{
if(n&1<<i) m++;//进行&运算,判断1,并计数
}
printf("%d\n",p[m]);
}
}
下面时位数运算
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n,cnt;
while(scanf("%d",&n)!=EOF)
{
cnt=0;
while(n)//当n=0时退出
{
if(n&1) cnt++;//从右比到左,进行&,与上不同的是,此时时移动n的位数
n>>=1;//每比一次,将n右移一位,注意不要写成n>>1(我的错)
}
printf("%d\n",1<<cnt);//输出2的cnt次方
}
}
鸣谢@清风拂山岗AC的指导