每日刷题(六十一)
ALGO-194、审美课
这个题绝对不可以用暴力破解法,这样会远远超出题目要求的时间。
我们可以换个角度看问题。要求答案完全相反的对数,而且给出的是1和0,我们很容易想到位运算这一类知识点。
由于最多20列,就相当于最大数是220-1,那么我们设一个数组ans来存数的种类的数目。这里有点难懂,没事,继续看就会懂了。我们首先要存数,但我们要处理一下,把传统思路的二维数组转化为一维数组,也就是一个同学的答案对应一个数,我们通过左移运算符每次传入一列的值就左移一次。最后再将得到的一个孩子的答案数字作为ans的下标,然后这个下标对应的值+1。
当值处理完后,我们用1 << m - 1得到答案最大的数字st(全1),然后进行n次循环,把每个a[i]与st异或一下,得到的数作为下标,sum += ans[cnt]
因为ans这个数组实际的意义就是存答案的重复次数,每个孩子的答案对应不同的下标,如果有很多孩子的答案都是这个数tmp,那么ans这个数值的下标的值就会很大。
注意,最终得到的sum要除以2,因为我们是遍历了n个孩子,如果存在完全相反的情况,那么我们的sum会重复加两次。
详细C代码如下:
#include<stdio.h>
#include<string.h>
int ans[1048576] = {0};
int a[50001];
int main()
{
int n, m;
scanf("%d %d", &n, &m);
memset(a, 0, sizeof(a));
int i, j;
for(i = 0; i < n; i++)
{
for(j = 0; j < m; j++)
{
int tmp;
scanf("%d", &tmp);
a[i] = (a[i] << 1) + tmp;
}
ans[a[i]]++;
}
int st = 0;
st = (1 << m) - 1; //全1
int sum = 0;
for(i = 0; i < n; i++)
{
int cnt;
cnt = a[i] ^ st; //异或得到完全相反的同学答案
sum += ans[cnt];
}
printf("%d\n", sum / 2);
return 0;
}
样例运行结果如下: