题目大意:
$n(nle1000)$个$m(mle5000)$位的二进制数,第$0$个数为$0$。用$wedge$和$vee$将这些数连接起来。$q(qle1000)$次询问,每次给定一个$m$位二进制数$r$,问有多少种连接方案使得结果为$r$。
思路:
参考myy的官方题解:
如果第$i$个数之前的运算符是$wedge$,则这一位设为$1$,否则为$0$,得到的二进制数记为$x$。
对每一位分别考虑,对于第$i$位,如果第$j$个数是$1$,那么这一位设为$1$,否则为$0$,得到的二进制数记为$b_i$。
以左边为最低位,按前缀归纳容易证明,第$i$位的结果为$1$,当且仅当$x<b_i$。
我们将$b$从大到小排序,结果设为$c$,那么答案不为零仅当在$c$的顺序下,$r$中没有任何$0$在$1$的前面。找到$r$中第一个$0$的位置,假设是$k$,那么解$x$要满足$c_kle x<c_{k-1}$,于是答案是$c_{k-1}-c_k$。
1 #include<cstdio> 2 #include<cctype> 3 #include<climits> 4 #include<algorithm> 5 #include<sys/mman.h> 6 #include<sys/stat.h> 7 typedef long long int64; 8 class MMapInput { 9 private: 10 char *buf,*p; 11 int size; 12 public: 13 MMapInput() { 14 register int fd=fileno(stdin); 15 struct stat sb; 16 fstat(fd,&sb); 17 size=sb.st_size; 18 buf=reinterpret_cast<char*>(mmap(0,size,PROT_READ,MAP_PRIVATE,fileno(stdin),0)); 19 p=buf; 20 } 21 char getchar() { 22 return (p==buf+size||*p==EOF)?EOF:*p++; 23 } 24 }; 25 MMapInput mmi; 26 inline int getint() { 27 register char ch; 28 while(!isdigit(ch=mmi.getchar())); 29 register int x=ch^'0'; 30 while(isdigit(ch=mmi.getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 31 return x; 32 } 33 inline int getdigit() { 34 register char ch; 35 while(!isdigit(ch=mmi.getchar())); 36 return ch^'0'; 37 } 38 const int N=1001,M=5000,mod=1e9+7; 39 int pow[M],rank[M],tmp[M],a[M],sum[M]; 40 int main() { 41 const int n=getint(),m=getint(),q=getint(); 42 for(register int i=0;i<m;i++) rank[i]=i; 43 for(register int i=pow[0]=1;i<=n;i++) { 44 pow[i]=pow[i-1]*2%mod; 45 } 46 for(register int i=0;i<n;i++) { 47 int cnt[2]={-1,m-1}; 48 for(register int j=0;j<m;j++) { 49 if(!(a[j]=getdigit())) cnt[0]++; 50 sum[j]=(sum[j]+(int64)a[j]*pow[i])%mod; 51 } 52 for(register int j=m-1;~j;j--) { 53 tmp[cnt[a[rank[j]]]--]=rank[j]; 54 } 55 std::swap(rank,tmp); 56 } 57 std::reverse(&rank[0],&rank[m]); 58 for(register int i=0;i<q;i++) { 59 for(register int i=0;i<m;i++) a[i]=getdigit(); 60 int last1=INT_MIN,first0=INT_MAX; 61 for(register int i=m-1;~i;i--) { 62 if(a[rank[i]]) { 63 last1=i; 64 break; 65 } 66 } 67 for(register int i=0;i<m;i++) { 68 if(!a[rank[i]]) { 69 first0=i; 70 break; 71 } 72 } 73 if(last1>first0) { 74 puts("0"); 75 continue; 76 } 77 const int sum1=last1==INT_MIN?pow[n]:sum[rank[last1]]; 78 const int sum2=first0==INT_MAX?0:sum[rank[first0]]; 79 printf("%d ",(sum1-sum2+mod)%mod); 80 } 81 return 0; 82 }