BAPC2014 K题 Key to Knowledge(中途相遇法,hash,状态压缩)

来源:互联网 发布:奥尔弗斯 知乎 编辑:程序博客网 时间:2024/06/05 09:45

题意: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;}





0 0
原创粉丝点击