Codeforces Round #44 (Div 2) D. Safe
問題概要
0,1の列からなるn文字のパスワードがある。
これに対してm個のn文字の0,1の列からなるパスワード誤入力の列および、
その列におけるパスワードと一致している文字数が与えられる。
(一致の個数だけで、どの位置が一致しているかは与えられない)
このとき、パスワードの文字列としてありうるものの個数を求めよ。
一致している文字数はそれぞれ5以下、n≤35,m≤10である。
解法
一つの誤入力文字列に着目する。
一致している文字は5以下なので、正しいパスワードの候補は35C5通り(=数十万)以下に絞れる。
よって、そのようなそのような候補を全て試してみることができる。
位置iの正誤をビットで表そうとするとlong longを使わないといけないことに注意する。
ソースコード
int n,m,cr[10],ans; string in[10]; bool ck(ll b){ rep(i,m){ int c=0; rep(j,n)if(in[i][j]-'0'==!!(b&1LL<<j))c++; if(c!=cr[i])return 0; } return 1; } void rec(int c,int u,ll b){ if(u>cr[0])return; if(c==n){ if(u<cr[0])return; rep(i,n)b^=1LL-(in[0][i]-'0')<<i; if(ck(b))ans++; return; } rec(c+1,u+1,b^1LL<<c); rec(c+1,u,b); } void run() { cin>>n>>m; pair<int,string> p[m]; rep(i,m)cin>>p[i].second>>p[i].first; sort(p,p+m); rep(i,m)cr[i]=p[i].first,in[i]=p[i].second; ans=0; rec(0,0,0); cout<<ans<<endl; }