2018百度之星資格賽- 1001調查問卷

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≤10​3​​,1 \leq m \leq 101≤m≤10,1 \leq k \leq 10^61≤k≤10​6​​,給定的 nn 份問卷互不相同。

Output

對於每組測試數據,輸出一行信息 "Case #x: y"(不含引號),其中 x 表示這是第 xx 組測試數據,y 表示滿足條件的問題集合的個數,行末不要有多餘空格。

Sample Input

2
2 2 1
AA
BB
2 2 2
AA
BB

Sample Output

Case #1: 3
Case #2: 0

 

 

這個題目讓我很慌...看了好久沒看懂題目...然後用map打完又顯示超時...這樣讓我很煩...前前後後改來改去提交超時了四次, 最後改寫法才成功AC.

這個題目就是一個找字串,然後判斷字串對數大於k的情況有多少種, 最後輸出有多少種情況...

對於具體如何遍歷有多少種組合 ,想必這個不用我說, 定義一個end = (1<<m)-1就行, 然後遍歷所有問題, 利用位運算選出被選中的問題是哪幾個.

最初我是額外定義一個char字符數組,  然後判斷當前字符串是否已經出現過, 如果沒有出現過, 說明前面的每一個字符串都可以和它組成一對, 假設當前遍歷到第i個數組, 那麼在這個地方就可以新出現 i-1對,  反之如果這個字符數組出現過, 那麼利用map.count得到它之前出現的次數cnt, 說明前面有cnt個字符串和它不能組成一對, 那麼說明在前面能和當前字符串組成一對的字符串有j - cnt個. 這樣一直遍歷到最後,如果對數大於K, 那麼答案+1.

這個是最初的想法, 驗證是錯誤, 但是超時我就很煩...直到後面ctrl+a   and delete重寫一遍...

因爲該題目中的問題只會有兩種結果A 和 B, 如果將A變成0,B換成1, 那麼它就變成了一個01串,並且每一張答卷因爲B出現的位置或者次數不同, 會有唯一的一個數代表它, 這樣,我們就可以用一個整數來代表一個字符串.

在後面遍歷每個字串的時候, 首先判斷這個問題是否已經被選取, 如果說沒有被選取, 那麼就判斷這個點是否爲B, 因爲在前面已經將A和B改成0和1了, 所以我們就判斷這個問題的結果是否爲1, 如果這個問題的結果爲1, 就利用一個整數將這個爲1的位置記錄下來

下面舉個栗子

假如說字符串是     0 0 0 1 1 1;

我們要選取的是     0 0 0 1 0 1;

然後定義一個整數 0 0 0 0 0 0

 從最左邊往右一直判斷, 這個位置是否被選取,同時這個位置是否爲B,

這樣就會得到結果 0 0 0 1 0 1  = 5,於是5就代表這個字符串, 其他任意的字符串結果都不會得到5這個數值.

同時注意到最大的位數爲10, 所以可以額外定義一個1100的整數數組, 初始化全爲0

記錄下每個數出現的次數, 也就是每種字符串出現的次數.

然後將每一種和另外的幾種連線, 爲了防止計算兩次, 

就定義i從0 到 1024進行遍歷, 初始有n個點

到遇到第一個不爲0的數的時候, 每個這個字符串能夠和後面n - sz[i]個字符串組成1對

所以就會有sz[i] * ( n-sz[i] )種方案. 後面的同理

下面貼代碼:

 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<map>
using namespace std;
const int maxn = 1005;
int t,n,m,k;
char sz[maxn][12];//存儲所有的字符串
int  cnt[2005];
char tp[12];
map<int,int> mp;
int main(){
	cin>>t;
	int e,i,j,c;
	for(c=1;c<=t;c++){
		scanf("%d %d %d",&n,&m,&k);
		for(i=0;i<n;i++){
			for(j=0;j<m;j++){
				scanf(" %c",&sz[i][j]);
				sz[i][j] -= 'A';
			}
		}
		//將字符串改成01串 
		e = (1<<m)-1;
		int tmp,ttmp,tans,p,sum=0,ans=0,g=0;
		
		for(i=1;i<=e;i++){
			memset(cnt,0,sizeof(cnt));
			for(j=0;j<n;j++){
				tmp=1,tans=0,ttmp=1;
				for(g=0;g<m;g++,tmp<<=1){ // 遍歷字符的每一位 
					if(sz[j][g] && (i&tmp)){
						tans |= tmp;
					}
				}
				//tans是這個字符串轉數字之後的結果
				cnt[tans]++;
			}
			
			ttmp=0,sum=0;
			for(j=1;j<=1024;j++)
				if(cnt[j]){ // 如果這個點不爲0的話
					ttmp += cnt[j];
					sum  += (n-ttmp)*cnt[j];
				}
			if(sum >= k) ans++;
		}
		printf("Case #%d: %d\n",c,ans);
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章