[bzoj5285][Hnoi2018]寻宝游戏——思维+排序

题目大意:

给定n个m位的二进制数,在每一个数前面补上一个\(\lor\)\(\land\),最前面补上一个0,每次询问最后运算结果为r的方案数为多少。

思路 :

感觉MYY出的题就是不一样。
位数很多,所以应该要想到对于每一位单独考虑。
对于单独每一位,考虑每一个运算符这一位上的影响,不难发现总共有四种情况:\(\land 1, \land 0, \lor 1, \lor 0\),其中\(\land 1,\lor 0\)对最后的结果不会产生影响,于是我们发现\(\land 0\)会使目前的结果为0,\(\lor 1\)会使目前的结果为1,并且每一次的运算独立,和之前的结果并没有任何关系。
于是可以进一步得到,如果最后的结果要为1,那么最后一个有效的运算应该是\(\lor 1\),如果是0,则最后一个有效的运算应该是\(\land 0\)
于是我们把操作序列的\(\land\)看作1,\(\lor\)看作0,并反转。然后将每一位的序列给从后往前提出来,不难发现当这一位的序列\(>\)opt的时候,这一位的结果为1,反之则为0。
于是我们只要对每一位的操作序列排序就好了。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define MREP(i,x) for(int i=beg[x],v;v=to[i],i;i=las[i])
#define debug(x) cout<<#x<<"="<<x<<endl
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
    freopen("bzoj5285.in","r",stdin);
    freopen("bzoj5285.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=1000+10;
const int maxm=5000+10;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
int n,m,q,rank[maxm];
ll p2[maxn],sum[maxm];
bool t[maxm];
struct node{
    int id;
    bool num[maxn];
    bool operator < (const node & tt) const {
        REP(i,1,n)if(num[i]<tt.num[i])return 1;
        else if(num[i]>tt.num[i])return 0;
        return 0;
    }
}a[maxm];

void init(){
    read(n); read(m); read(q);
    p2[0]=1;
    REP(i,1,n)p2[i]=p2[i-1]*2%mod;
    REP(i,1,n){
        char ch=getchar();
        int cnt=0;
        while(!isdigit(ch))ch=getchar();
        while(isdigit(ch))a[++cnt].num[n-i+1]=ch^'0',ch=getchar();
    }
    REP(i,1,m)a[i].id=i;
    sort(a+1,a+m+1);
    REP(i,1,m)rank[a[i].id]=i;
    //REP(i,1,m)printf("%d\n",rank[i]);
    /*REP(i,1,m){
        //printf("%d\n",a[i].id);
        REP(j,1,n)printf("%d",a[i].num[j]);
        putchar('\n');
    }*/
}

void work(){
    REP(i,1,n)a[m+1].num[i]=1;
    REP(i,1,m+1)REP(j,1,n)if(a[i].num[j])
        sum[i]=(sum[i]+p2[n-j])%mod;
    ++sum[m+1];
    REP(ca,1,q){
        char ch=getchar();
        int cnt=0,L=0,R=m+1;
        while(!isdigit(ch))ch=getchar();
        while(isdigit(ch))t[++cnt]=ch^'0',ch=getchar();
        REP(i,1,m)if(t[i])R=min(R,rank[i]);
        else L=max(L,rank[i]);
        //cout<<L<<" "<<R<<endl;
        if(L>R)printf("0\n");
        else printf("%lld\n",(sum[R]-sum[L]+mod)%mod);
        /*REP(i,1,n)cout<<t[i];
          cout<<endl;*/
    }
}

int main(){
//	File();
    init();
    work();
    return 0;
}
posted @ 2018-12-05 19:22  ylsoi  阅读(151)  评论(0编辑  收藏  举报