题意:
有N个学生。有M题目
然后相应N行分别有一个二进制和一个整数
二进制代表该同学给出的每道题的答案。整数代表该同学的答案与标准答案相符的个数
要求推断标准答案有几个,假设标准答案仅仅有一种。则输出标准答案
思路:
非常easy想到状态压缩。可是非常明显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(" "); } else printf("%d solutions ",ans); } return 0; }