[HNOI/AHOI2018]寻宝游戏

题目大意:
  $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 }
原文地址:https://www.cnblogs.com/skylee03/p/8858304.html