2018百度之星程序设计大赛资格赛——1001调查问卷

HDU-6344

Problem Description

度度熊为了完成毕业论文,需要收集一些数据来支撑他的论据,于是设计了一份包含 m 个问题的调查问卷,每个问题只有 'A' 和 'B' 两种选项。

将问卷散发出去之后,度度熊收到了 n 份互不相同的问卷,在整理结果的时候,他发现可以只保留其中的一部分问题,使得这 n 份问卷仍然是互不相同的。这里认为两张问卷是不同的,当且仅当存在至少一个被保留的问题在这两份问卷中的回答不同。

现在度度熊想知道,存在多少个问题集合,使得这 n 份问卷在只保留这个集合的问题之后至少有 k 对问卷是不同的。

Input

第一行包含一个整数 T,表示有 T 组测试数据。

接下来依次描述 T 组测试数据。对于每组测试数据:

第一行包含三个整数 n,m 和 k,含义同题目描述。

接下来 n 行,每行包含一个长度为 m 的只包含 'A' 和 'B' 的字符串,表示这份问卷对每个问题的回答。

保证 1≤T≤100,1≤n≤103,1≤m≤10,1≤k≤106,给定的 n 份问卷互不相同。

Output

对于每组测试数据,输出一行信息 "Case #x: y"(不含引号),其中 x 表示这是第 x 组测试数据,y 表示满足条件的问题集合的个数,行末不要有多余空格。

Sample Input

 

2 2 2 1 AA BB 2 2 2 AA BB

Sample Output

 

Case #1: 3 Case #2: 0

状态压缩dp的应用

//
//  main.cpp
//  P1001
//
//  Created by jinyu on 2018/8/9.
//  Copyright © 2018年 jinyu. All rights reserved.
//

#include <iostream>
using namespace std;
const int MAXN = 1000+7;    //问卷份数的最大值 1000
const int MAXS = 1024+7;    //状态最大值为 2的10次方

char s[17];
int value[MAXN];    //value[i] 表示第i份问卷的值,A用 “1” 表示,B用 “0” 表示
int visit[MAXS];    //visit[i] 表示在当前问题集合的情况下,状态i出现的次数
int dp[MAXN][MAXS];     //dp[i][state]表示当前state状态在前i份问卷一共有对多少不同

int main(){
    int T;
    scanf("%d",&T);
    int tt = T;
    while(tt--){
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i = 1;i<=n;i++){
            value[i] = 0;
            scanf("%s",s+1);
            for(int j = 1;j<=m;j++){
                if(s[j]=='A'){
                    value[i]+=(1<<(m-j));
                }
            }
        }
        printf("Case #%d: ",T-tt);
        if(n*(n-1)/2 < k)   printf("0\n");  //n取2的组合数一共有 n*(n-1)/2 种
        else{
            memset(dp, 0, sizeof(dp));
            int ans = 0;
            
            //state表示选中的问题集合,1则代表该问题被选中
            //通过按位与&运算,state & value[j] 得到当前state问题集合下问题的答案
            //按位与运算的应用:可以获取指定位的数值,如:x&100101 可以得到x的第1,4,6位的数值
            //状态转移:dp[j][state] = dp[j-1][state] + (j-1) - visit[nowValue];
            // dp[j][state]: 假定第j份和前面j-1份都不同,则可以产生j-1对不同的问卷,加上dp[j-1][state],然后去掉重复的,即减去visit[nowValue]
            
            for(int state = 1;state<(1<<m);++state){    //问题集合至少选1个问题,至多选全部问题
                memset(visit, 0, sizeof(visit));
                for(int j = 1;j<=n;j++){
                    int nowValue = state & value[j];    //得到当前state问题集合下问题的答案
                    dp[j][state] = dp[j-1][state] + (j-1) - visit[nowValue];
                    visit[nowValue]++;
                }
                if(dp[n][state]>=k) ans++;
            }
            printf("%d\n",ans);
        }
        
    }
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41508508/article/details/81538319