蓝桥杯 算法训练 审美课
题目链接:http://lx.lanqiao.cn/problem.page?gpid=T519
思路
1.暴力求解:
题目的时间限制为1s,对于二重循环,n最大可以取到2500,题目中的n最大可取的50000,因此暴力法不能得满分
2.二进制取反:
用二进制存储的思路如下:
1.将每个学生的答案用数组b[i]以二进制的形式存储。故答案相同的学生数组b[i]存的值是相同的。例如某同学的答案为0101001,则b[i]等于0101001表示的十进制整数41。
2.数组ans[b[i]]用于存储每种答案的人数。例如,假设ans[3]=10,即有10个人答案相同且答案都为3 。
3.按行遍历(此时为一重循环),令MAX=(2 ^ m)-1(此时^表示次方运算,装逼一点的写法是MAX=1<<m-1),对每一行的b[i]取反,可以用b[i] ^MAX(在c++中 ^ 表示异或,简单一点的写法是MAX-b[i] ),与取反后的答案相同的 即为题目要求的完全相反的答案 (例如,m=3,即MAX=7,若b[i]=4,取反后为7-4=3,若ans[3]=10,则所有答案中与4完全不同的有10个。
4.最后sum/2是因为重复计算了,除以2之后才是“有多少对同学”。
代码
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define ll long long
using namespace std;
int ans[20000000]= {0};//2^20次方约等于1000万,数组的大小不得小于2^20
int b[60000]= {0};//大于5000即可
int main() {
int n,m,sum=0;//i,j一般都作为循环变量,最好在循环用到时再申明
cin>>n>>m;
int MAX=pow(2,m)-1;//pow(i,j)=i的j次方
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
int t;
cin>>t;
b[i]=b[i]*2+t;//计算每个答案的十进制数值
}
int t=b[i];
ans[t]++;//统计每种答案的个数
}
for(int i=0; i<n; i++) {
int t=b[i]^MAX;//取反
sum+=ans[t];
}
cout<<sum/2<<endl;
return 0;
}
部分思路参考:https://blog.csdn.net/weixin_42324771/article/details/87533713