2020大一寒假ACM培训④(二进制枚举篇)

二进制?枚举?二进制枚举?听都没听过。
然而在我还没搞懂的时候,大佬们已经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;
}

终于把之前鸽的博客都更完了!
二进制枚举真快乐!今天依旧是仰望大佬的一天!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值