1. 程式人生 > >【BZOJ】5285: [Hnoi2018]尋寶遊戲 -找規律/拆位

【BZOJ】5285: [Hnoi2018]尋寶遊戲 -找規律/拆位

傳送門:bzoj5285


題解

首先考慮拆出一位來觀察性質:

o r   0 or\ 0 a n

d   1 and \ 1 不會使原數變化。
o r   1
or\ 1
a n d   0 and \ 0 會使原數變為 1
1
/ 0 0 ,而與原數無關。

可以把操作看做一個01串 T ( 0 > o r , 1 > a n d ) T(0->or ,1->and) ,而設 S S 為1-n的原串中這一位取出來得到的01串。若 S S 中連續一段 [ l , r ] [l,r] T T 相等,則經過這一段操作後仍存在值 = S l 1 =S_{l-1}

若值最後 = 1 =1 ,則必然 o r   1 or \ 1 出現在 a n d   0 and\ 0 之後。
將第 n n 位作為最高位,要求就變成了 S > T S>T

若值最後 = 0 =0 ,則 S T S\leq T 。直接統計即可。


程式碼

#include<bits/stdc++.h>
using namespace std;
const int N=5010,mod=1e9+7;

int n,m,qe,a[N],b[N],s[N],bin[N],c[2];
char q[N];

inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}

int main(){
	int i,j,l,r;
	scanf("%d%d%d",&n,&m,&qe);
	for(i=1;i<=m;++i) a[i]=i;
	bin[1]=1;for(i=2;i<=n;++i) bin[i]=ad(bin[i-1],bin[i-1]);
	for(i=1;i<=n;++i){
		scanf("%s",q+1);c[1]=m;c[0]=0;
		for(j=1;j<=m;++j) q[j]=='1'?(s[j]=ad(s[j],bin[i])):(c[0]++);
		for(j=m;j;--j) b[c[q[a[j]]-'0']--]=a[j];
		for(j=1;j<=m;++j) a[j]=b[j];
    }
    s[m+1]=ad(bin[n],bin[n]);a[m+1]=m+1;
    for(;qe;--qe){
    	scanf("%s",q+1);l=0;r=m+1;
    	for(i=m;i;--i) if(q[a[i]]=='0') {l=i;break;}
    	for(i=1;i<=m;++i) if(q[a[i]]=='1') {r=i;break;}
    	printf("%d\n",l>=r?0:dc(s[a[r]],s[a[l]]));
    }
    return 0;
}