zoukankan      html  css  js  c++  java
  • 蓝桥杯(算法训练)

    审美课  

    时间限制:1.0s   内存限制:256.0MB
    问题描述
      《审美的历程》课上有n位学生,帅老师展示了m幅画,其中有些是梵高的作品,另外的都出自五岁小朋友之手。老师请同学们分辨哪些画的作者是梵高,但是老师自己并没有答案,因为这些画看上去都像是小朋友画的……老师只想知道,有多少对同学给出的答案完全相反,这样他就可以用这个数据去揭穿披着皇帝新衣的抽象艺术了(支持帅老师^_^)。
      答案完全相反是指对每一幅画的判断都相反。
    输入格式
      第一行两个数n和m,表示学生数和图画数;
      接下来是一个n*m的01矩阵A:
      如果aij=0,表示学生i觉得第j幅画是小朋友画的;
      如果aij=1,表示学生i觉得第j幅画是梵高画的。
    输出格式
      输出一个数ans:表示有多少对同学的答案完全相反。
    样例输入
    3 2
    1 0
    0 1
    1 0
    样例输出
    2
    样例说明
      同学1和同学2的答案完全相反;
      同学2和同学3的答案完全相反;
      所以答案是2。
    数据规模和约定
      对于50%的数据:n<=1000;
      对于80%的数据:n<=10000;
      对于100%的数据:n<=50000,m<=20。
     

     
    使用暴力法只得了70分,最后三个测试用力不通过,需要使用二进制存储的思路:
     
    将每个学生的答案用数组a[i]以二进制的形式存储(二进制011对应的是3)。则答案相同的学生在数组a[i]存的值是相同的。
    数组res[ a[i] ]用于存储每种答案的人数。例如,假设res[3]=10,即有10个人答案相同且答案都为3 (十进制3对应的二进制为011)。
    按行遍历,按位取反,与取反后的答案相同的,即为题目要求的完全相反的答案。
    最后sum/2是因为重复计算了,除以2之后才是“有多少对同学”。
     
    注意
    乍一看,取反不是“~”吗,为什么用的异或运算符“^”?
    异或运算符的规则是:相反为1,相同为0,即:0^0=0, 1^0=1, 0^1=1, 1^1=0
    所以无论1还是0,与1异或就实现了取反操作。故可以实现按位取反
     
    源代码:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 int a[50000];    //最大输入50000个学生
     5 int res[1048580]={0};    //一共20副画图数,最多有2的20次方来存储 ,类似于筛选法 
     6 int sum=0;    //计算最终结果 
     7 
     8 int main()
     9 {
    10     //freopen("input.txt","r",stdin) ;
    11     int n,m;
    12     cin>>n>>m;
    13     for(int i=0;i<n;i++)
    14     {
    15         for(int j=0;j<m;j++)
    16         {
    17             int temp;
    18             cin>>temp;
    19             a[i]=(a[i]<<1)+temp; 
    20         }
    21         res[a[i]]++;
    22     }
    23     
    24     int max=(1<<m)-1;    //构造m位全为1的二进制,如3位,向左移动3位就为8,8-1=7的二进制为111 ,刚好为三位 
    25     for(int i=0;i<n;i++)
    26     {
    27         int tmp=a[i]^max; 
    28         sum+=res[tmp];
    29     } 
    30     
    31     cout<<sum/2;    //    循环时候每个数d 
    32     //fclose(stdin);
    33     return 0;
    34 } 

    思路2:异或运算和map

    用二进制表示每位同学的回答。(m<=20;2^20 在int的范围内)。

    相反的答案用二进制与m个1,1,1.....1(即2^m-1)的数maxn取异或即可。(如 01 == 1 ,10 == 2,2^3 == 1(异或),1^3 == 2 )

    因为map默认是按key值从小到大排序的,则可以直接在遍历map中取0~maxn/2即可。

    设m个1,1,1.....1(即2^m-1)的数为maxn,mid = maxn/2; 通过枚举你会发现 maxn^x = maxn-x = y (x,y属于[0,maxn]),(maxn与x逐位取异或 实际就是逐位做减法,因为maxn全为1(1>={0,1}),不存在减法借位的),如(111-010 = 101 = 111^010),则[0,mid]的一个数x与maxn取异的值y一定在(mid,maxn]中。如(maxn = 7, 7^0=7 - 0 = 7、7^1=7-1=6、7^2=7-2=5).

    如果你遍历了map中的[0~mid]那么后面的就不需要再遍历了,因为后面map中能与[0~mid]匹配的值肯定已经被匹配过了。此步骤可要可不要,不会影响实际的通过。

     1 #include <bits/stdc++.h> 
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     //freopen("input.txt","r",stdin);
     7     ios::sync_with_stdio(false);
     8     
     9     map<int,int> ans;
    10     
    11     int n,m;
    12     cin>>n>>m;
    13     
    14     for(int i=0;i<n;i++)
    15     {
    16         int num=0;
    17         int x;
    18         for(int j=0;j<m;j++)
    19         {
    20             cin>>x;
    21             num=(num<<1)+x;    //将输入的一行0或者1转换为二进制数 (十进制表示)
    22         }
    23         ans[num]++;     //将每个对应的二进制数key的value+1,value默认为0 
    24     } 
    25     
    26     int sum=0,maxn=(1<<m)-1,mid=maxn/2; 
    27     
    28     for(map<int,int>::iterator it=ans.begin();it!=ans.end();++it)
    29     {
    30         int x=it->first;
    31         if(x>mid)    //map默认是按key值从小到大排序的,则可以直接在遍历map中取0~maxn/2即可,[0,mid]的一个数x与maxn取异的值y一定在(mid,maxn]中 
    32         {
    33             break;
    34         }
    35         int temp=x^maxn;    ////构造m位全为1的二进制,如3位,向左移动3位就为8,8-1=7的二进制为111 ,刚好为三位 
    36         sum+=ans[temp]*it->second;    //需要将当前的相同的个数和与他取反的数的个数相乘才是有多少个 
    37     }
    38     cout<<sum;
    39     
    40     //fclose(stdin);
    41     return 0;
    42 }
  • 相关阅读:
    洗礼灵魂,修炼python(20)--自定义函数(1)—基础概念
    洗礼灵魂,修炼python(19)--文件I/O操作,linecache,fileinput模块
    洗礼灵魂,修炼python(18)--温故加知新
    洗礼灵魂,修炼python(17)--跨平台操作三剑客—os,os.path.sys模块
    洗礼灵魂,修炼python(16)--列表进阶话题—>上节作业讲解+copy模块,浅拷贝,深拷贝
    洗礼灵魂,修炼python(15)--列表进阶话题—>列表解析/列表生成器
    洗礼灵魂,修炼python(14)--模块decimal, fractions,operator,collections以及精度介绍
    洗礼灵魂,修炼python(13)--模块random,math,pickle
    748. Shortest Completing Word
    542. 01 Matrix
  • 原文地址:https://www.cnblogs.com/WindSun/p/10503278.html
Copyright © 2011-2022 走看看