2018 百度之星資格賽 1001 調查問卷
阿新 • • 發佈:2018-11-02
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=6344
題意:給n份問卷,每個問卷m道題,每題只有A,B兩種選項,問存在多少個問題集合,使得只保留這些問題後至少k對卷子不同。
題解:剛開始做的時候,沒有什麼思路,因為要求至少K對,我對這個點無從下手,後來比賽結束看了下別人的部落格,原來可以用一個叫做狀態壓縮dp的東西來求解,用二進位制去列舉問題集合,有2^m種情況,
然後要確定狀態方程,dp[i][j]含義:對於前i個問卷,在問題集合j上,有多少對問卷不同
轉移狀態為:dp[i][j]=dp[i-1][j]+i-vis[tt];
其中,vis[tt]的含義:前i個問卷(包括i)中與第i個問卷中的問題集合狀態相同的數目
#include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <set> #include <map> #include <queue> #include <algorithm> #include <cmath> #define maxn 1505 #define maxz 2005 #define INF 0x3f3f3f3f #define LL long long using namespace std; int n,m,k; int dp[maxn][maxn]; string s[maxn]; int vis[maxn]; int main() { int t; cin>>t; int cnt=1; while(t--) { cin>>n>>m>>k; for(int i=1;i<=n;i++) { cin>>s[i]; } for(int u=0;u<(1<<m);u++) { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { int tt=0; for(int j=0;j<m;j++) { if(u&(1<<j)&&s[i][j]=='A') { tt|=1<<j; } } vis[tt]++; dp[i][u]=dp[i-1][u]+i-vis[tt]; } } LL ans=0; for(int i=0;i<(1<<m);i++) { if(dp[n][i]>=k) { ans++; } } cout << "Case #" << cnt++ << ": "; cout << ans << endl; } return 0; }