码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-13 01:15:12      阅读:271      评论:0      收藏:0      [点我收藏+]

标签:hunnu

题意:

有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 rank1
const 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;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:hunnu

原文地址:http://blog.csdn.net/libin56842/article/details/47459449

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!