2018"百度之星"程序设计大赛 - 资格赛 1001 调查问卷 二进制状态压缩
调查问卷
Accepts: 401
Submissions: 1731
Time Limit: 6500/6000 MS (Java/Others)
Memory Limit: 262144/262144 K (Java/Others)
Problem Description
度度熊为了完成毕业论文,需要收集一些数据来支撑他的论据,于是设计了一份包含 mm 个问题的调查问卷,每个问题只有 'A' 和 'B' 两种选项。
将问卷散发出去之后,度度熊收到了 nn 份互不相同的问卷,在整理结果的时候,他发现可以只保留其中的一部分问题,使得这 nn 份问卷仍然是互不相同的。这里认为两张问卷是不同的,当且仅当存在至少一个被保留的问题在这两份问卷中的回答不同。
现在度度熊想知道,存在多少个问题集合,使得这 nn 份问卷在只保留这个集合的问题之后至少有 kk 对问卷是不同的。
Input
第一行包含一个整数 TT,表示有 TT 组测试数据。
接下来依次描述 TT 组测试数据。对于每组测试数据:
第一行包含三个整数 nn,mm 和 kk,含义同题目描述。
接下来 nn 行,每行包含一个长度为 mm 的只包含 'A' 和 'B' 的字符串,表示这份问卷对每个问题的回答。
保证 1 \leq T \leq 1001≤T≤100,1 \leq n \leq 10^31≤n≤103,1 \leq m \leq 101≤m≤10,1 \leq k \leq 10^61≤k≤106,给定的 nn 份问卷互不相同。
Output
对于每组测试数据,输出一行信息 "Case #x: y"(不含引号),其中 x 表示这是第 xx 组测试数据,y 表示满足条件的问题集合的个数,行末不要有多余空格。
Sample Input
Copy
2 2 2 1 AA BB 2 2 2 AA BB
Sample Output
Case #1: 3 Case #2: 0
状态压缩
每张问卷填写的结果转换成一个二进制数x,选择哪些题也变成一个二进制数y(选择第i题,则i位为1),则x&y就是调查问卷x在选择的题状态为y的情况下填的问卷, 用一个数组存在选题状态为y下,每种问卷的个数。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define fora(i,a,b) for(i=a;i<b;i++)
#define fors(i,a,b) for(i=a;i>b;i--)
#define fora2(i,a,b) for(i=a;i<=b;i++)
#define fors2(i,a,b) for(i=a;i>=b;i--)
#define PI acos(-1.0)
#define eps 1e-6
#define INF 0x3f3f3f3f
typedef long long LL;
typedef long long LD;
using namespace std;
const int maxn=1e3+11;
char q[15];
int a[1024][1024];
int main()
{
int T,t=0,len;
scanf("%d",&T);
while(T--)
{
int n,m,k;//问卷1e3,问题10,不同1e6
scanf("%d%d%d",&n,&m,&k);
int i,j,M=1<<m;
memset(a,0,sizeof(a));
fora2(i,1,n)
{
scanf("%s",q);
int tem=0;
fora(j,0,m)
{
tem=tem*2+q[j]-'A';
}
fora(j,1,M)
{
a[j][tem&j]++;
}
}
int ans=0;
printf("Case #%d: ",++t);
if(n*(n-1)/2<k)printf("0\n");
else
{
fora(i,1,M)
{
int sum=n*(n-1)/2;
fora(j,0,M)
{
int tem=a[i][j];
sum-=tem*(tem-1)/2;
}
if(sum>=k)ans++;
}
printf("%d\n",ans);
}
}
return 0;
}