【中途相遇法】【STL】BAPC2014 K Key to Knowledge (Codeforces GYM 100526)
题目链接:
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),每个学生的答题情况和正确题数已知,求标准答案可能有多少种。
如果标准答案只有一种则输出标准答案,否则输出解的个数。
题目思路:
【中途相遇法】【STL】
如果枚举每道题的正误时间复杂度是O(N*2M),肯定T了。所以考虑中途相遇法。
首先枚举前M/2道题的标准答案的正误,统计出每个状态每个学生的正确题数。
(答案的状态用二进制压缩,学生的正确题数用31进制压缩)先把每个学生答对题数的状态存进ss里
之后用一个map存下当前学生正确题数状态有几种符合条件的,并且存下任意一种答案的状态。
接下来枚举剩下的M-M/2道题目,统计学生正确题数的状态x,判断ss-x是否出现过(即前M/2道题有没有能够与现在匹配的状态),出现过则ans加上出现次数。
最后根据ans数量输出即可。
1 // 2 //by coolxxx 3 //#include<bits/stdc++.h> 4 #include<iostream> 5 #include<algorithm> 6 #include<string> 7 #include<iomanip> 8 #include<map> 9 #include<memory.h> 10 #include<time.h> 11 #include<stdio.h> 12 #include<stdlib.h> 13 #include<string.h> 14 //#include<stdbool.h> 15 #include<math.h> 16 #define min(a,b) ((a)<(b)?(a):(b)) 17 #define max(a,b) ((a)>(b)?(a):(b)) 18 #define abs(a) ((a)>0?(a):(-(a))) 19 #define lowbit(a) (a&(-a)) 20 #define sqr(a) ((a)*(a)) 21 #define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b)) 22 #define mem(a,b) memset(a,b,sizeof(a)) 23 #define eps (1e-8) 24 #define J 10 25 #define mod 1000000007 26 #define MAX 0x7f7f7f7f 27 #define PI 3.14159265358979323 28 #define N 14 29 #define M 34 30 using namespace std; 31 typedef long long LL; 32 int cas,cass; 33 int n,m,lll,ans; 34 char s[N][M]; 35 int a[N],l[N],r[N]; 36 int f[65544]; 37 int z; 38 LL ss; 39 map<LL,int>num,t; 40 void init() 41 { 42 int i,j; 43 for(i=1;i<=(1<<16);i++) 44 for(j=i;j;j>>=1) 45 f[i]+=(j&1); 46 } 47 int main() 48 { 49 #ifndef ONLINE_JUDGE 50 // freopen("1.txt","r",stdin); 51 // freopen("2.txt","w",stdout); 52 #endif 53 int i,j,k; 54 LL x; 55 init();//统计每个数字2进制下有几个1 56 for(scanf("%d",&cass);cass;cass--) 57 // for(scanf("%d",&cas),cass=1;cass<=cas;cass++) 58 // while(~scanf("%s",s+1)) 59 // while(~scanf("%d",&n)) 60 { 61 scanf("%d%d",&n,&m); 62 ans=0;mem(l,0);mem(r,0);num.clear();t.clear(); 63 for(i=1;i<=n;i++) 64 scanf("%s%d",s[i],&a[i]); 65 for(i=1,ss=0;i<=n;i++) 66 ss=ss*31+a[i]; 67 cas=m/2; 68 for(i=1;i<=n;i++) 69 { 70 for(j=0;j<cas;j++) 71 l[i]=l[i]*2+s[i][j]-'0';//前m/2道题 72 for(j=cas;j<m;j++) 73 r[i]=r[i]*2+s[i][j]-'0';//后m-m/2道题 74 } 75 for(j=0;j<(1<<cas);j++) 76 { 77 for(i=1,x=0;i<=n;i++) 78 { 79 x=x*31+cas-f[l[i]^j];//31进制,前m/2道题状态为j的n个人的答对题数,f[l[i]^j]为错误题数 80 if(cas-f[l[i]^j]>a[i])break; 81 } 82 if(i<=n)continue; 83 num[x]++;t[x]=j<<(m-cas);//学生的状态数num和这个状态下题目答案的状态t 84 } 85 cas=m-cas; 86 for(j=0;j<(1<<cas);j++) 87 { 88 for(i=1,x=0;i<=n;i++) 89 { 90 x=x*31+cas-f[r[i]^j];//f[r[i]^j]为错误题数 91 if(cas-f[r[i]^j]>a[i])break; 92 } 93 if(i<=n)continue; 94 if(num[ss-x])//与前面的状态匹配 95 { 96 ans+=num[ss-x]; 97 z=t[ss-x]+j; 98 } 99 } 100 if(ans==1) 101 { 102 for(i=(1<<(m-1));i;i>>=1) 103 printf("%d",((i&z)==i)); 104 puts(""); 105 } 106 else printf("%d solutions\n",ans); 107 } 108 return 0; 109 } 110 /* 111 // 112 113 // 114 */