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

题意:

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

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

时间: 2024-10-01 01:05:38

BAPC2014 K&&HUNNU11591:Key to Knowledge(中途相遇法)的相关文章

【中途相遇法】【STL】BAPC2014 K Key to Knowledge

题目链接: http://codeforces.com/gym/100526 http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11674&courseid=0 题目大意: N个学生M道题(1<=N<=12,1<=M<=30),每道题只有正误两种选项(0 1),每个学生的答题情况和正确题数已知,求标准答案可能有多少种. 如果标准答案只有一种则输出标准答案,否则输出解的个数. 题目思路: [

uva 6757 Cup of Cowards(中途相遇法,貌似)

uva 6757 Cup of CowardsCup of Cowards (CoC) is a role playing game that has 5 di?erent characters (Mage, Tank, Fighter,Assassin and Marksman). A team consists of 5 players (one from each kind) and the goal is to kill amonster with L life points. The

Codeforces Round #297 (Div. 2) E题. Anya and Cubes (中途相遇法)

题目地址:Anya and Cubes 比赛的时候居然没想起中途相遇法...这题也是属于想起来就很简单系列. 中途相遇法也叫折半搜索.就是处理前一半,把结果储存起来,再处理后一半,然后匹配前一半存储的结果. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib

HDU 5936 Difference 【中途相遇法】(2016年中国大学生程序设计竞赛(杭州))

Difference Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 62    Accepted Submission(s): 19 Problem Description Little Ruins is playing a number game, first he chooses two positive integers y an

codeforces 525 E Anya and Cubes 中途相遇法

codeforces 525 E Anya and Cubes 中途相遇法 题意: 给出n个数a1,a2,...,an,要求从中选出一些数,可以把其中最多k个变成它自己的阶乘,然后选出的数求和,问最后和等于s的选法有多少种. 限制: 1 <= n <= 25; 0 <= k <= n; 1<= s <= 1e16; 1 <= ai <= 1e9 思路: 一般数据量20~30都会考虑中途相遇法,就是折半暴力. ps:用三进制暴力会比直接深搜多一个常数10,因为

uva1152 - 4 Values whose Sum is 0(枚举,中途相遇法)

用中途相遇法的思想来解题.分别枚举两边,和直接暴力枚举四个数组比可以降低时间复杂度.可是我不会写...看了紫书作者刘汝佳老师的代码,真是太美了!简单明了,就像看吕钦下的棋一样.我就模仿的写了一下: #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set>

POJ 1840 Eqs Hash + 中途相遇法

把等式分成两拨算用中途相遇法就好了. 不过要注意的是这里不能用map,会超时,要自己手写hash,我重载了[]操作符之后用起来和map差不多,很随意 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <string> #include <qu

J 中途相遇法,求和

---恢复内容开始--- J - 中途相遇法 Time Limit:9000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description The SUM problem can be formulated as follows: given four lists A, B, C, D<tex2html_verbatim_mark> of integer values, compute

Codeforces 31E TV Game 中途相遇法 状压dp

题目链接:点击打开链接 题意: 给定2*n长的数字. 把这个数字拆成2个长度为n的数字,且相对位置不变.使得拆后得到的2个数字的和最大. 输出一个方案. 显然是中途相遇法,先计算左半段,再计算右半段 分别状压左半段和右半段,注意左半段状压后要在末尾补上0. 代码估计哪里有小越界==,数组开大了一点才过..具体就不查了. #include<iostream> #include<stdio.h> #include<string.h> #include<string&g