BAPC2014 K&&HUNNU11591:Key to Knowledge(中途相遇法)

来源:互联网 发布:知客是什么意思 编辑:程序博客网 时间:2024/06/06 05:26

题意:

有N个学生,有M题目

然后对应N行分别有一个二进制和一个整数

二进制代表该同学给出的每道题的答案,整数代表该同学的答案与标准答案相符的个数

要求判断标准答案有几个,如果标准答案只有一种,则输出标准答案


思路:

很容易想到状态压缩,但是很明显1<<30纯粹的状压是会超时的,那么我们可以优化一半,变成1<<15

也就是说,对于一个串,我们分半处理

首先处理前一半,讨论前一半与标准答案相符的状况,然后再讨论后半串,看与标准答案相符的情况能不能与前一半相匹配,从而算出答案


#include <iostream>#include <stdio.h>#include <string.h>#include <stack>#include <queue>#include <map>#include <set>#include <vector>#include <math.h>#include <bitset>#include <algorithm>#include <climits>using namespace std;#define ls 2*i#define rs 2*i+1#define UP(i,x,y) for(i=x;i<=y;i++)#define DOWN(i,x,y) for(i=x;i>=y;i--)#define MEM(a,x) memset(a,x,sizeof(a))#define W(a) while(a)#define gcd(a,b) __gcd(a,b)#define LL long long#define ULL unsigned long long#define N 100005#define INF 0x3f3f3f3f#define EXP 1e-8#define rank rank1const int mod = 1000000007;int t,n,m;char str[50][50];int a[50];LL num[50][2];int hsh[1<<16]= {0};int main(){    int i,j,k;    for(i = 0; i<(1<<16); i++)//hsh记录1的个数    {        t = i;        while(t)        {            hsh[i]+=t%2;            t/=2;        }    }    scanf("%d",&t);    while(t--)    {        LL ans = 0;        map<LL,int> cnt;        map<LL,int> state;        scanf("%d%d",&n,&m);        for(i = 0; i<n; i++)        {            scanf("%s%d",str[i],&a[i]);            num[i][0]=num[i][1] = 0;            for(j = 0; j<m/2; j++)//记录前一半的2进制状态                num[i][0] = num[i][0]*2+(str[i][j]-'0');            for(j = m/2; j<m; j++)//记录后一半的2进制状态                num[i][1] = num[i][1]*2+(str[i][j]-'0');        }        //前半部的处理        int s = m/2;        for(i = 0; i<(1<<s); i++)        {            LL tem = 0;            for(j = 0; j<n; j++)            {                k = hsh[i^num[j][0]];//与答案不相同的个数                if(s-k>a[j]) break;                tem = tem*30+s-k;//30进制存状态            }            if(j==n)            {                cnt[tem]++;//该状态有几种                state[tem] = i;            }        }        s = m-s;//后一半        int s1,s2;        for(i = 0; i<(1<<s); i++)        {            LL tem = 0;            for(j = 0; j<n; j++)            {                k = hsh[i^num[j][1]];                if(s-k>a[j]) break;                tem = tem*30+a[j]-(s-k);//找回前一半的状态            }            if(j==n&&cnt[tem])            {                ans+=cnt[tem];                s1 = state[tem];                s2 = i;            }        }        if(ans==1)        {            stack<int> Q;            for(i = 0; i<s; i++)            {                Q.push(s2%2);                s2/=2;            }            for(i = 0; i<m-s; i++)            {                Q.push(s1%2);                s1/=2;            }            while(!Q.empty())            {                printf("%d",Q.top());                Q.pop();            }            printf("\n");        }        else            printf("%d solutions\n",ans);    }    return 0;}


0 0
原创粉丝点击