Problem Description
度度熊为了完成毕业论文, 需要收集一些数据来支撑他的论据, 于是设计了一份包含 mm 个问题的调查问卷, 每个问题只有'A' 和'B' 两种选项.
将问卷散发出去之后, 度度熊收到了 nn 份互不相同的问卷, 在整理结果的时候, 他发现可以只保留其中的一部分问题, 使得这 nn 份问卷仍然是互不相同的. 这里认为两张问卷是不同的, 当且仅当存在至少一个被保留的问题在这两份问卷中的回答不同.
现在度度熊想知道, 存在多少个问题集合, 使得这 nn 份问卷在只保留这个集合的问题之后至少有 kk 对问卷是不同的.
Input
第一行包含一个整数
T
T, 表示有
T
T 组测试数据.
接下来依次描述
T
T 组测试数据. 对于每组测试数据:
第一行包含三个整数
n
n,
m
m 和
k
k, 含义同题目描述.
接下来 nn 行, 每行包含一个长度为 mm 的只包含'A' 和'B' 的字符串, 表示这份问卷对每个问题的回答.
保证 1 \leq T \leq 1001T100,1 \leq n \leq 10^31n10?3??,1 \leq m \leq 101m10,1 \leq k \leq 10^6
1
k
1
0
?
6
??, 给定的
n
n 份问卷互不相同.
Output
对于每组测试数据, 输出一行信息 "Case #x: y"(不含引号), 其中 x 表示这是第 xx 组测试数据, y 表示满足条件的问题集合的个数, 行末不要有多余空格.
- Sample Input
- 2
- 2 2 1
- AA
- BB
- 2 2 2
- AA
- BB
- Sample Output
- Copy
- Case #1: 3
- Case #2: 0
参考博客: https://blog.csdn.net/nuclear_physis/article/details/81414833
分析: 我们将 A-B 的问题序列转化成为 0-1 二进制序列从而转为整数特征, 而问题子集情况也可以使用 0-1 进制序列表示. 通过位运算就可以表示问题子集对应的问题结果 0-1 序列, 进而转为整数特征. 先将 n 个问卷的问题特征值排序. 排序后就可以清晰得到相同问题问卷数目, 比如有这样的排序结果 [1 2 2 3 3], 那么问卷 2 和 3 的问题是一样的, 问卷 4 和 5 的是一样的. 通过相同问题数目就可以很容易得到相同问题问卷的对数. 我们想如果将总的问题对数减去相同的问题的问卷对数那么就得到了不一样问卷的对数. 上面的例子就是 5 * 4 / 2 - 2 * 1 / 2 - 2 * 1 / 2 等于 8.
AC 代码:
- #include <bits/stdc++.h>
- using namespace std;
- int T,n,m,k;
- int answers[1010];
- int process_answers[1010];
- void replace(string &s){
- for (int i=0; i<m; i++){
- if (s[i] == 'A') {
- s[i] = '1';
- } else if (s[i] == 'B') {
- s[i] = '0';
- }
- }
- }
- bool judge(int save_flag) {
- // 对于原问题进行保留处理
- for (int i=0; i<n; i++) {
- process_answers[i] = answers[i] & save_flag;
- }
- // 统计每一个问题结果出现次数
- map<int,int> count_fre;
- for (int i=0; i<n; i++) {
- if (count_fre.count(process_answers[i])> 0) {
- count_fre[process_answers[i]] += 1;
- } else {
- count_fre[process_answers[i]] = 1;
- }
- }
- // 利用总对数减去相同问题结果对数
- int total = n * (n - 1) / 2;
- for (map<int, int>::iterator iter = count_fre.begin(); iter != count_fre.end(); iter++) {
- int cnt = iter->second;
- if (cnt>= 2) {
- total -= (cnt * (cnt - 1) / 2);
- }
- }
- if (total>= k) {
- return true;
- } else {
- return false;
- }
- }
- void print(int casei, int res){
- printf("Case #%d: %d\n",casei, res);
- }
- int main() {
- scanf("%d",&T);
- for (int casei = 1; casei<=T; casei++) {
- scanf("%d%d%d",&n,&m,&k);
- for (int i=0; i<n; i++) {
- string s;
- cin>> s;
- replace(s);
- bitset<11> bs(s);
- answers[i] = bs.to_ulong();
- }
- int l = 1, r = (1 << m) - 1, res = 0;
- for (int i = l; i <= r; i++) {
- if (judge(i)) {
- res += 1;
- }
- }
- print(casei,res);
- }
- return 0;
- }
来源: http://www.bubuko.com/infodetail-2714577.html