• [bzoj5285] [HNOI2018]寻宝游戏


    Description

    某大学每年都会有一次Mystery Hunt的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会。

    作为新生的你,对这个活动非常感兴趣。你每天都要从西向东经过教学楼一条很长的走廊,这条走廊是如此的长,以至于它被人戏称为infinite corridor。一次,你经过这条走廊时注意到在走廊的墙壁上隐藏着nn个等长的二进制的数字,长度均为m。你从西向东将这些数字记录了下来,形成一个含有n个数的二进制数组a1,a2,...,an。

    很快,在最新的一期的Voo Doo杂志上,你发现了qq个长度也为mm的二进制数r1,r2,...,rq。

    聪明的你很快发现了这些数字的含义。

    保持数组a_1,a_2,...,a_na1,a2,...,an的元素顺序不变,你可以在它们之间插入∧(按位与运算)或者∨(按位或运算)。例如:11011∧00111=00011,11011∨00111=11111。

    你需要插入n个运算符,相邻两个数之前恰好一个,在第一个数的左边还有一个。如果我们在第一个运算符的左边补入一个0,这就形成了一个运算式,我们可以计算它的值。与往常一样,运算顺序是从左到右。有趣的是,出题人已经告诉你这个值的可能的集合——Voo Doo杂志里的那些二进制数r1,r2,...,rq,而解谜的方法,就是对r1,r2,...,rq中的每一个值ri,分别计算出有多少种方法填入这n个计算符,使的这个运算式的值是ri。

    然而,infinite corridor真的很长,这意味着数据范围可能非常大。因此,答案也可能非常大,但是你发现由于谜题的特殊性,你只需要求答案模1000000007的值。

    Input

    第一行三个数n,m,q,含义如题所述。

    接下来n行,其中第ii行有一个长度为m的二进制数,左边是最高位,表示ai。

    接下来q行,其中第ii行有一个长度为m的二进制数,左边是最高位,表示ri。

    Output

    输出q行,每行一个数,其中的i行表示对于ri的答案。

    Solution

    考虑第(i)位,显然可以发现,答案一定被最后一个(&0)或者(|1)操作所决定,剩下的两个操作对答案并无影响。

    然后设操作序列(s),操作为(&)时为1,(|)时为0。

    设每个串的第(i)为构成的串为(t)

    那么比较操作序列(s)(t)可得:从后往前数第一个不同的地方决定答案。

    然后可以发现这个过程其实就是从后往前比较(s)(t)的字典序。

    (s>t),则答案为0,否则为1。

    所以把(t)从大到小排一遍序,对于一个答案序列(r),按照(t)的位置调整一下,找到第一个0和最后一个1,位置记为(l,r)

    (l<r),显然没有方案满足,否则操作区间就是((s(r+1),s(r)]),所以统计下答案就好了。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 5e3+10;
    const int maxm = 2e4+10;
    const int mod = 1e9+7;
    
    int n,m,len,rev[maxm],q,tmp[maxn];
    char str[maxn][maxm],in[maxn];
    
    struct node{
        int a[maxn/30],ans,id;
        bool operator < (const node &rhs) const {
            for(int i=len;~i;i--) if(a[i]!=rhs.a[i]) return a[i]>rhs.a[i];
            return 0;
        }
    }s[maxm];
    
    int qpow(int a,int x) {
        int res=1;
        for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
        return res;
    }
    
    signed main() {
        read(n),read(m),read(q);len=n/30;
        for(int i=1;i<=n;i++) scanf("%s",str[i]+1);
        for(int i=1;i<=m;i++) {
            for(int j=n;j;j--) {
                s[i].a[j/30]=(s[i].a[j/30]<<1)|(str[j][i]-'0');
                s[i].ans=(2ll*s[i].ans+str[j][i]-'0')%mod;
            }
            s[i].id=i;
        }
        sort(s+1,s+m+1);
        s[0].ans=qpow(2,n);
        for(int i=1;i<=m;i++) rev[s[i].id]=i;
        for(int i=1;i<=q;i++) {
            scanf("%s",in+1);int l=0,r=0;
            for(int j=1;j<=m;j++) tmp[rev[j]]=in[j]-'0';
            for(int j=m;j;j--) if(tmp[j]) {r=j;break;}
            for(int j=1;j<=m;j++) if(!tmp[j]) {l=j;break;}
            if(l<r&&l&&r) puts("0");
            else write(((s[r].ans-s[r+1].ans)%mod+mod)%mod);
        }
        return 0;
    }
    
  • 相关阅读:
    公号文章模板
    css 网格线
    刷题笔记-图-图的存储
    PAT Advanced A1021 Deepest Root (25) [图的遍历,DFS,计算连通分量的个数,BFS,并查集]
    PAT Advanced 1013 Battle Over Cities (25) [图的遍历,统计连通分量的个数,DFS,BFS,并查集]
    PAT Advanced 1076 Forwards on Weibo (30) [图的遍历,BFS,DFS]
    PAT Advanced 1034 Head of a Gang (30) [图的遍历,BFS,DFS,并查集]
    堆排序
    PAT Advanced 1155 Heap Paths (30) [DFS, 深搜回溯,堆]
    PAT Advanced 1098 Insertion or Heap Sort (25) [heap sort(堆排序)]
  • 原文地址:https://www.cnblogs.com/hbyer/p/10171129.html
Copyright © 2020-2023  润新知