题意:n个学生和m道选择题,每个学生有关于m个选择题的答案,表示为一个字符串,1位√ 0位X,后面给一个老师给的对了几个答案
现在给你n个学生的答案,问,一共有多少种可能的答案,如果只有一个答案输出解
思路:一开始是直接暴力,当然TLE。当时没想到更好的办法了...后面看了别人写的题解是中途相遇法才恍然大悟,很巧妙。把一个 串分成两个串,前面一半部分的结果放在hash里面,然后再去枚举后面一半部分的所有状态即可。
具体可以看代码
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
int n,m;
struct Node
{
char op[35];
int k;
} p[15];
map<long long,int>mp;
long long h[1<<16];
void solve()
{
mp.clear();
for(int i=0; i<(1<<(m/2)); i++)
{
long long x=0;
for(int j=0; j<n; j++)
{
int num=p[j].k;
for(int k=0; k<m/2; k++)
if(((i>>k)&1)==(p[j].op[k]=='1'))
num--;
if(num<0)
{
x=-1;
break;
}
x=x*(m+1)+num;
}
if(x==-1) continue;
h[i]=x;
mp[x]++;
}
int cnt=0,ans;
for(int i=0; i<(1<<(m-m/2)); i++)
{
long long x=0;
for(int j=0; j<n; j++)
{
int num=0;
for(int k=m/2; k<m; k++)
if(((i>>(k-m/2))&1)==(p[j].op[k]=='1'))
num++;
x=x*(m+1)+num;
}
if(!cnt&&mp[x]>0)
{
for(int j=0; j<(1<<(m/2)); j++)
if(h[j]==x)
ans=j+(i<<(m/2));///记得加括号
}
cnt+=mp[x];
}
if(cnt!=1) printf("%d solutions\n",cnt);
else
{
for(int i=0; i<m; i++)
printf("%d",(ans>>i)&1);
printf("\n");
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=0; i<n; i++)
scanf("%s %d",p[i].op,&p[i].k);
solve();
}
return 0;
}