• bzoj 5285 [HNOI2018] 寻宝游戏


    bzoj 5285 [HNOI2018] 寻宝游戏

    Solution

    这题太可怕了

    想不到

    按位考虑

    对于当某一位,(& 1,| 0) 这两种操作对当前数完全没有影响,我们只要找到倒着第一次的 (&0,| 1),或者根本就没有这样的玩意

    我们如果想让这一位是 (1),那么就得让倒着第一次的 (& 0,| 1) 一定是 (| 1),而且必须出现(否则就是 (0) 做了一堆不变的操作,最后还是 (0)

    我们考虑把操作按照倒序写成 (01) 串,就是 (|) 写成 (0)(&) 写成 (1)

    假设当前考虑第 (i) 位,我们令 (s =overline {s_{n,i}s_{n-1,i}s_{n-2,i}dots s_{1,i}})(是一个 (01) 串),发现当且仅当操作序列串字典序小于等于 (s) 的时候,这一位的结果最后是 (1),字典序大于 (s) 的时候,这一位最后等于 (0)

    那么对于当前询问,变成了对于每一位都有一个操作序列小于等于一个串或者大于一个串的限制

    统计一下上下界就好了

    具体实现见代码

    Code

    // Copyright lzt
    #include<stdio.h>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<string>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef std::pair<int, int> pii;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef std::pair<long long, long long> pll;
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define rep(i, j, k)  for (register int i = (int)(j); i <= (int)(k); i++)
    #define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
    #define Debug(...) fprintf(stderr, __VA_ARGS__)
     
    inline ll read() {
      ll x = 0, f = 1;
      char ch = getchar();
      while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
      }
      while (ch <= '9' && ch >= '0') {
        x = 10 * x + ch - '0';
        ch = getchar();
      }
      return x * f;
    }
     
    const int maxn = 5050;
    const int mod = 1e9 + 7;
    int n, m, q;
    char str[maxn];
    int val[maxn][1010], num[maxn], rnk[maxn];
     
    bool cmp(int x, int y) {
      rrep(i, n, 1) 
        if (val[x][i] != val[y][i])
          return val[x][i] > val[y][i];
      return x < y;
    }
     
    void work() {
      n = read(), m = read(), q = read();
      rep(i, 1, n) {
        scanf("%s", str + 1);
        rep(j, 1, m) val[j][i] = str[j] - '0';
      }
      int full = 1;
      rep(i, 1, n) full = full * 2 % mod;
      rep(i, 1, m) rrep(j, n, 1) {
        num[i] = (num[i] * 2 + val[i][j]) % mod;
      }
      rep(i, 1, m) rnk[i] = i;
      sort(rnk + 1, rnk + m + 1, cmp);
      while (q--) {
        scanf("%s", str + 1);
        bool f = 0, flag = 0;
        rep(i, 1, m) {
          if (str[rnk[i]] == '0') f = 1;
          else if (f) {
            puts("0");
            flag = 1;
          }
          if (flag) break;
        }
        if (flag) continue;
        rep(i, 1, m) {
          if (str[rnk[i]] == '0') {
            if (i == 1) printf("%d
    ", (full - num[rnk[i]] + mod) % mod);
            else printf("%d
    ", (num[rnk[i - 1]] - num[rnk[i]] + mod) % mod);
            flag = 1;
          }
          if (flag) break;
        }
        if (!flag) printf("%d
    ", num[rnk[m]]);
      }
    }
     
    int main() {
      #ifdef LZT
        freopen("in", "r", stdin);
      #endif
     
      work();
     
      #ifdef LZT
        Debug("My Time: %.3lfms
    ", (double)clock() / CLOCKS_PER_SEC);
      #endif
    }
    

    Review

    神仙题

    对于有关位运算和 (01) 串的题,都可以尝试按位考虑

    至于这道题怎么想到字典序的。。。只有出题人能想到系列。。。

  • 相关阅读:
    Nodejs 开发指南 Nodejs+Express+ejs 开发microblog开发心得
    转载 java学习注意点
    STM32f103的数电采集电路的ADC多通道采集程序
    时间复杂度与空间复杂度
    RS232串口通信详解
    实现扫码登录
    TCP/UDP区别与联系
    Tcp三次握手/四次挥手
    浅谈CSRF攻击方式
    图片淡入淡出
  • 原文地址:https://www.cnblogs.com/wawawa8/p/10162869.html
Copyright © 2020-2023  润新知