• 【题解】HNOI2018寻宝游戏


      太厉害啦……感觉看到了正解之后整个人都惊呆了一样。真的很强%%%

      首先要注意到一个性质。位运算列与列之间是不会相互影响的,那么我们先观察使一列满足条件的操作序列需要满足什么条件。&0时,不论之前是什么数字,结果都是0,而|1时,结果都是1。我们现在将&用1表示,而|用0表示。这样我们将我们&|的操作序列转化为了一个01串。假设这一列数字操作出来做后的结果应当是1,显然有最后的一个|1在&0之后。我们比较一下两个串,同为1或者同为0则跳过(&1 和 |0 不影响数字的大小),然后当出现操作序列是1而数字序列是0时,就一定不合法;反之则一定合法(|1 和 &0 谁先出现)。

      写到这里不知道有没有感觉出一点什么?其实就是在比较两个串的字典序啊。结果为1:操作串字典序 < 数字序列字典序;结果为0 :操作串字典序 >= 数字序列字典序。到这里正解就呼之欲出了:将所有的数字串(一列上的)按反序(自底向上)字典序排列,此后只要求出临界的两个字符串,答案就是这两个字符串的数字差啦。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 1105
    #define maxm 5105
    #define mod 1000000007
    #define ll long long
    #define int long long
    ll n, m, q, sum[maxm], MAXX;
    char Q[maxm], S[maxm];
    
    struct node
    {
        int id;
        char a[maxn];
    }ch[maxm];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    bool cmp(node a, node b)
    {
        for(int i = 1; i <= n; i ++)
        {
            int k1 = a.a[i] - '0', k2 = b.a[i] - '0';
            if(k1 == k2) continue;
            else if(k1 > k2) return 0;
            else return 1;
        }
    }
    
    ll Get_num(int x) //y - x
    {
        int ret1 = 0;
        for(int i = 1; i <= n; i ++)
        {
            ret1 = ret1 * 2 % mod;
            if(ch[x].a[i] - '0') ret1 += 1;
        }
        return ret1;
    }
    
    ll Qpow(int x, int t)
    {
        ll base = 1;
        for(; t; t >>= 1, x = (x * x) % mod)
            if(t & 1) base = (base * x) % mod;
        return base;
    }
    
    signed main()
    {
        n = read(), m = read(), q = read();
        MAXX = Qpow(2, n);
        for(int i = 1; i <= n; i ++)
        {
            scanf("%s", S + 1);
            for(int j = 1; j <= m; j ++)
                ch[j].a[n - i + 1] = S[j];
        }
        for(int i = 1; i <= m; i ++) ch[i].id = i;
        sort(ch + 1, ch + 1 + m, cmp);
        for(int i = 1; i <= m; i ++)
            sum[i] = Get_num(i);
        for(int i = 1; i <= q; i ++)
        {
            scanf("%s", Q + 1);
            int mark1 = 0, mark2 = 0;
            for(int j = 1; j <= m; j ++)
                if(Q[ch[j].id] - '0') 
                {
                    mark1 = j;
                    break;
                }
            for(int j = m; j >= 1; j --)
            {
                if(!(Q[ch[j].id] - '0')) 
                {
                    mark2 = j;
                    break;
                }
            }
            if(mark1 && mark2 && mark2 >= mark1) printf("0
    ");
            else 
            {
                if(mark1) printf("%lld
    ", (sum[mark1] - sum[mark2] + mod) % mod);
                else if(!mark1 && mark2) printf("%lld
    ", (MAXX - sum[mark2] + mod) % mod);
                else printf("%lld
    ", MAXX);
            }
        }
        return 0;
    } 
  • 相关阅读:
    Cookie操作
    C# 操作Cookie类
    面向对象之struct
    高薪程序员都避开了那些坑【安晓辉】
    [转]C#之反射
    [转]正则表达式相关:C# 抓取网页类(获取网页中所有信息)
    membership 在web.config中配置信息
    面向对象之virtual
    面向对象之多态
    JAVA面向对象 接口
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8910959.html
Copyright © 2020-2023  润新知