注解
1、注意题目范围,m<=10,想到状态压缩。把10个问题的A、B字符串转换成二进制数保存。(用位运算)
代码:(A转换为1,B转换为0),1<<(len-k-1),表示1左移len-k-1位,也就是把1乘上2的(len-k-1)次方。
for(int j=1; j<=n; j++){
string s;
cin>>s;
int len = s.length();
for(int k=0; k<len; k++){
if(s.at(k)=='A'){
a[j] += (1<<(len-k-1));
}
}
}
3、依次枚举每个可能的子集(选择部分问题的情况),与每张问卷的这个子集情况下的答案匹配。当匹配到第j张问卷时,如果第j张与前面的j-1张问卷有cnt张(包括第j张)状态相同,也就是有j-cnt张状态不同,那么也就是有j-cnt对满足题目条件的。当某个子集状态枚举完成后求和,如果大于k,这种子集就是符合题意的一种情况。遍历所有可能的子集,就得到最终的答案。
代码:status是最大可能的枚举状态。now是当前状态与当前问卷的 与,也就是当前问卷在当前状态子集上的答案集合。sum表示截至到当前这张问卷,共有多少对不同的问卷答案。ans是最终要求的状态数。
int status = 1<<m;
for(int s=1; s<=status; s++){
int cnt[status+1];
memset(cnt, 0, sizeof(cnt));
int sum = 0;
for(int j=1; j<=n; j++){
int now = s&a[j];
cnt[now]++;
sum += j-cnt[now];
}
if(sum>=k){
ans++;
}
}
代码
#include <iostream>
#include <cstring>
using namespace std;
int main(){
int T;
cin>>T;
for(int i=1; i<=T; i++){
int n, m, k;
cin>>n>>m>>k;
int a[n+1];
memset(a, 0, sizeof(a));
for(int j=1; j<=n; j++){
string s;
cin>>s;
int len = s.length();
for(int k=0; k<len; k++){
if(s.at(k)=='A'){
a[j] += (1<<(len-k-1));
}
}
}
int ans = 0;
int status = 1<<m;
for(int s=1; s<=status; s++){
int cnt[status+1];
memset(cnt, 0, sizeof(cnt));
int sum = 0;
for(int j=1; j<=n; j++){
int now = s&a[j];
cnt[now]++;
sum += j-cnt[now];
}
if(sum>=k){
ans++;
}
}
cout<<"Case #"<<i<<": "<<ans<<endl;
}
return 0;
}