二进制?枚举?二进制枚举?听都没听过。
然而在我还没搞懂的时候,大佬们已经AK了。
OTR OTR OTR
ACM培训(大佬鉴赏大赛)真快乐!
让我这个小菜鸡先来搞懂什么是二进制枚举吧。
一、二进制操作
算数位运算:
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。二进制中的左移就是除二操作(舍去小数)。
三、二进制枚举
直接参见吧
二进制枚举–最通俗易懂的讲解
彻底搞懂二进制枚举
好了,现在开始被题目虐爆吧。
Problem A NEFU OJ 643 teacher Li
字符串的异或。
#include <bits/stdc++.h>
using namespace std;
int n,k,i,j;
string a,ans;
int main()
{
k=0;
while(cin>>n>>ans)
{
for(i=1;i<2*n-1;i++)
{
cin>>a;
for(j=0;j<max(a.size(),ans.size());j++)
ans[j]^=a[j];
}
printf("Scenario #%d\n",++k);
cout<<ans<<endl<<endl;
}
return 0;
}
Problem B NEFU OJ 1172 Find different
普通的异或。
#include <bits/stdc++.h>
using namespace std;
long long ans,n,x,s;
int main()
{
while(scanf("%lld",&n)!=EOF)
{
scanf("%lld",&ans);
n--;
while(n--)
{
scanf("%d",&x);
ans=ans^x;
}
printf("%lld\n",ans);
}
return 0;
}
Problem C NEFU OJ 1205 和为K
这题注意大小。
二进制!枚举!
#include <bits/stdc++.h>
using namespace std;
int n,a[1000000];
long long k,s;
int main()
{
int i,j,f;
while(cin>>n>>k)
{
for(i=0;i<n;i++)
{
cin>>a[i];
}
for(i=0;i<(1<<n);i++)
{
s=0;
f=1;
for(j=0;j<n;j++)
{
if(i&(1<<j))
s+=a[j];
}
if(s==k)
{
printf("Yes");
printf("\n");
f=0;
break;
}
}
if(f==1)
{printf("No");
printf("\n");}
}
return 0;
}
Problem D NEFU OJ 1505 陈老师加油
(吐槽下题目名字为什么不叫陈老师奥力给。)
依旧二进制枚举。
#include <bits/stdc++.h>
using namespace std;
int t;
int main()
{
long i,j,f,tmp;
int jyz,lk;
while(cin>>t)
{
f=0;
for(i=0;i<(1<<15);i++)
{
jyz=lk=0;
tmp=t;
for(j=0;j<15;j++)
{
if(i&(1<<j))
{
jyz++;
tmp=tmp*2;
}
else
{
lk++;
tmp--;
if(tmp<=0)
break;
}
}
if(jyz==5&&lk==10&&tmp==0)
f++;
}
cout<<f<<endl;
}
return 0;
}
Problem E NEFU OJ 1518 纸牌游戏
#include <bits/stdc++.h>
using namespace std;
int s,f,a[25];
int main()
{
int n,p,i,j;
while(scanf("%d%d",&n,&p)!=EOF)
{
f=0;
for(i=0; i<n; i++)
{
cin>>a[i];
}
for(i=0; i<(1<<n); i++)
{
s=0;
for(j=0; j<n; j++)
{
if(i&(1<<j))
{
s+=a[j];
}
}
if(s==p)
{
f++;
}
}
printf("%d\n",f);
}
return 0;
}
Problem F NEFU OJ 1641 权利指数
这个题需要多读几遍题。
#include <bits/stdc++.h>
using namespace std;
int n,t,a[25],b[25],s,sum;
int main()
{
int i,j;
cin>>t;
while(t--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
cin>>n;
sum=0;
for(i=0; i<n; i++)
{
cin>>a[i];
sum+=a[i];
}
for(i=0; i<(1<<n); i++)
{
s=0;
for(j=0; j<n; j++)
{
if(i&(1<<j))
{
s+=a[j];
}
}
if(s>(sum/2))
{
for(j=0; j<n; j++)
if(i&(1<<j))
{
if((s-a[j])<=(sum/2))
b[j]++;
}
}
}
for(i=0; i<n; i++)
{printf("%d",b[i]);
if(i!=n-1)
printf(" ");
}
printf("\n");
}
return 0;
}
Problem G NEFU OJ 1285 趣味解题
一道数学期望题。
说实话题目描述没看懂。
#include <bits/stdc++.h>
using namespace std;
int t,cnt,x;
double a[15],b[15],c[15],wa[15],ac[15],p,ans;
int main()
{
int i,j,n;
cin>>t;
while(t--)
{
cin>>n;
for(i=0;i<n;i++)
scanf("%lf",&a[i]);
for(i=0;i<n;i++)
scanf("%lf",&b[i]);
for(i=0;i<n;i++)
scanf("%lf",&c[i]);
cin>>x;
ans=0;
for(i=0;i<(1<<n);i++)
{
p=1;cnt=0;
for(j=0;j<n;j++)
{
wa[j]=(1-a[j])*(1-b[j])*(1-c[j]);
ac[j]=1-wa[j];
if(i&(1<<j))
{
p=p*ac[j];
cnt++;
}
else
p=p*wa[j];
}
if(cnt==x)
ans+=p;
}
printf("%.4lf\n",ans);
}
return 0;
}
终于把之前鸽的博客都更完了!
二进制枚举真快乐!今天依旧是仰望大佬的一天!