东北林业大学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、异或运算
异或如果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)
就是对二进制每一位进行了一次异或操作,即非进位加法。
5、异或运算
例题:nefu1172
题意:
一共有n个数 ,有1个数只出现一次,其他数出现偶数次。
解析:
设一个答案数,其他输入对他进行异或即可。
核心代码:

移位操作有两种左移与右移:
1、左移<<
例如:A=5(0101)
如果向左移动一位即A<<1结果为1010,十进制的10。二进制中的左移就是乘二操作,在c/c++中左移运算速度比乘二速度要快。
2、右移>>
例如:A=5(0101)
如果向右移动一位即A>>1结果为0010,十进制的2。二进制中的左移就是除二操作(舍去小数)。
异或:
林大oj 643 teacher Li//多组输入,每次输出多输出一个回车
林大oj 1172 Find different//多组
二进制枚举:
林大oj 1205 和为k//多组
林大oj 1285 趣味解题
林大oj 1505 陈老师加油
林大oj 1641 权利指数

林大oj 1518 纸牌游戏

Give an odd number n, (1<=n<=10000001)

Given you an array which have n numbers : a[1], a[2] a[3] … a[n].They are positive num.
There are n/2 numbers which appear twice and only one number appears once.
Now you should tell me the number which appears only once.
Input
There are several test cases end with EOF.
The first line there is a integer n.
Then the 2nd line there are n integer a[1],a[2]…a[n].
Output
For each case, output the number which appears only once.
Sample Input
7
3 2 7 2 1 7 3
1
7
11
1 1 2 2 3 3 4 4 5 5 9
Sample Output
1
7
9

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int main()
{  int i,j,a,m,x;
int n;

while(scanf("%d\n",&n)!=-1)
{scanf("%d",&x);
    for(i=1;i<n;i++)
    {  scanf("%d",&a);


        x=x^a;【利用异或的规则,不难发现偶次出现的为0,利用0异或任何人一个数就变成这个数,相同数异或将当于不变】

    }

 printf("%d\n",x);
}
    return 0;
}

陈老师经常开车在哈尔滨的大街上行走,假设刚开始油箱里有T升汽油,每看见加油站陈老师就要把汽油的总量翻倍(就是乘2);每看见十字路口气油就要减少1升;最后的时候陈老师的车开到一个十字路口,然后车就没油了------就熄火了,陈老师好痛苦啊~~~!
然后他就开始回忆,一路上一共遇到5个加油站,10个十字路口,问造成这种惨烈的境遇有多少种可能?

Input
输入一个T ,(1<=T<=100);
Output
输出可能的方案数。
Sample Input
1

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int i,j,t,l,n,m,way;


int main()
{
while(~scanf("%d",&n))
  {

way=0;
    for(i=0;i<(1<<15);i++)
    {   t=n; l=m=0;
        for(j=0;j<15;j++)
        {
            if(i&(1<<j))
               {
                 t=t*2;
              l++;
               }
               else {t=t-1;m++;}
if(t==0)
       break;
        }


       if(t==0&l==5&&m==10)
       {
           way++;
       }
    }
printf("%d\n",way);

  }

    return 0;
}

给出长度为n的数组,求能否
从中选出若干个,使他们的和为K.如果可以,输出:Yes,否则输出No
Input
第一行:输入N,K,为数组的长度和需要判断的和(2<=N<=20,1<=K<=10^9)
第二行:N个值,表示数组中元素的值(1<=a[i]<=10^6)
Output
输出Yes或No
Sample Input
5 13
2 4 6 8 10
Sample Output
No

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int main()
{  int i,j,t,l;
int n,k;
int a[21];
while(~scanf("%d ",&n))
  {scanf("%d\n",&k);
     l=0;t=0;
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(i=0;i<(1<<n);i++)
    {  t=0;
        for(j=0;j<n;j++)
        {
            if(i&(1<<j))
                t=t+a[j];
        }
       if(t==k)
       {
           printf("Yes");l++;
          break;
       }
    }

 if(l==0)
    printf("No");
  }

    return 0;
}

给你一些扑克,每张都对应一个点数,分别对应1-13,K 就是13;J 是11;Q是12;
现在想从这些扑克牌中取出一些牌,让这些牌的点数的和等于一个幸运数值P,问有多少种方案?
Input
输入数据第一行为n和p,分别代表n张扑克牌和幸运数(1<=n<=20,p<=260)
接下来是这n张牌的点数; 1<=点数<=13;
Output
输出能得到P 的方案数?
Sample Input
5 5
1 2 3 4 5
Sample Output
3
Hint

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int n,p,i,j,t,way;
int a[21];
int main()
{   while(scanf("%d %d",&n,&p)!=-1)
    {
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    way=0;
    for(i=0;i<(1<<n);i++)
    {    t=0;
        for(j=0;j<n;j++)
        {
            if(i&(1<<j))
            {
                t=t+a[j];
            }

        }if(t==p)【判断是否相同需要在第二个if外面】
        {way++;}
   }
    printf("%d",way);
}

    return 0;
}

在选举问题中,总共有n个小团体,每个小团体拥有一定数量的选票数。如果其中m个小团体的票数和超过总票数的一半,则此组合为“获胜联盟”。n个团体可形成若干个获胜联盟。一个小团体要成为一个“关键加入者”的条件是:在其所在的获胜联盟中,如果缺少了这个小团体的加入,则此联盟不能成为获胜联盟。一个小团体的权利指数是指:一个小团体在所有获胜联盟中成为“关键加入者”的次数。请你计算每个小团体的权利指数。
Input
输入数据的第一行为一个正整数T,表示有T组测试数据。每一组测试数据的第一行为一个正整数n(0<n<=20)。第二行有n个正整数,分别表示1到n号小团体的票数。
Output
对每组测试数据,在同一个行按顺序输出1到n号小团体的权利指数。
Sample Input
2
1
10
7
5 7 4 8 6 7 5
Sample Output
1
16 22 16 24 20 22 16

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int i,j,n,t,b,m;
int sum;
int a[21],str1[21],str2[21];
int main()
{
   scanf("%d\n",&t);
  while(t--)
   {
    scanf("%d\n",&n);
    sum=0;
   for(i=0;i<n;i++)
   {

       scanf("%d",&a[i]);
       sum=sum+a[i];
   }
   for(i=0;i<n;i++)
   {
       str2[i]=0;
   }
   for(i=0;i<(1<<n);i++)
   {    m=0;memset(str1,0,sizeof(str1));
       for(j=0;j<n;j++)
       {
           if(i&(1<<j))
            {m=m+a[j];
           str1[j]=1;}【标记加过的数,将题意化简为先算小于中和一半再找加上这个数后变为大于总和一半】

       }

      if(m<=sum/2)
      {
          for(j=0;j<n;j++)
          {
              if(m+a[j]>sum/2&&str1[j]==0)【将加过的排除在外】
                str2[j]++;

          }
      }
    }
   for(i=0;i<=n-2;i++)
   {printf ("%d ",str2[i]);}
   printf("%d\n",str2[n-1]);

   }

    return 0;
}

现在假设你正在参加ACM程序设计大赛,这场比赛有 n 个题目,对于第 i 个题目你有 a_i 的概率AC掉它,如果你不会呢,那么这时候队友的作用就体现出来啦,队友甲有 b_i 的概率AC掉它, 队友乙有 c_i 的概率AC掉它,那么现在教练想知道你们队伍做出 x 个题目的概率。
Input
输入一个正整数T(T<=100),表示有T组数据,对于每组数据首先输入一个 n (7<=n<=13),表示有 n 个题目,接下来输入三行,
第一行输入 n 个数a_i,第二行输入 n 个数b_i,第三行输入 n 个数c_i, 其中 a_i, b_i, c_i 的意义如题,最后输入一个 x 表示教练想要知道你们队伍做出的题目数(x>=0)。
Output
输出一行表示结果,保留4位小数
Sample Input
2
7
0.1 0.2 0.3 0.4 0.5 0.6 0.7
0.2 0.3 0.4 0.5 0.6 0.7 0.8
0.3 0.4 0.5 0.6 0.7 0.8 0.9
1
7
0.1 0.2 0.3 0.4 0.5 0.6 0.7
0.2 0.3 0.4 0.5 0.6 0.7 0.8
0.3 0.4 0.5 0.6 0.7 0.8 0.9
5
Sample Output
0.0000
0.2811

```cpp
//【我自己码的,啊哈哈哈哈哈哈哈哈哈哈哈】
#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int i,j,n,x,t,l;
double sum,m;
double a[100][100],b[100],p[100],dp[15][15];
int main()
{
   scanf("%d\n",&t);
  while(t--)
   {
    scanf("%d\n",&n);
    for(j=1;j<=3;j++)
    {  for(i=1;i<=n;i++)
       { scanf("%lf",&a[j][i]);
       }
    }
    scanf("%d",&x);
    for(i=0;i<n;i++)
       { b[i]=(1-a[2][i+1])*(1-a[1][i+1])*(1-a[3][i+1]);}
    m=0;
    for(i=0;i<(1<<n);i++)
    {  sum=1;l=0;
        for(j=0;j<n;j++)
        {
            if(i&(1<<j))
                {sum=sum*(1-b[j]);l++;}
                else
                    sum=sum*b[j];

        }
        if(l==x)

          m=m+sum;
    }

    printf("%.4lf\n",m);

   }

    return 0;}
【给出来的题解】

#include <bits/stdc++.h>
using namespace std;
int t,n,x,i,j,cnt;
double a[15],b[15],c[15],ac[15],wa[15],ans,p;
【ac[i]表示团队做对第i题的概率,wa[i]表示团队做错第i题的概率】
int main()
{
    cin>>t;
    while(t--)
    {
        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;cnt=0;
            for(j=0;j<n;j++)
            {
                wa[j]=(1-a[j])*(1-b[j])*(1-c[j]);[3个人都不会做这题,即团队做不出这题的概率】
                ac[j]=1-wa[j];
                if(i&(1<<j))
                {p=p*ac[j];cnt++;}【cnt记录团队ac数量】
                else
                    p=p*wa[j];
            }
            if(cnt==x)
                ans=ans+p;
        }
        printf("%.4lf\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值