zoukankan      html  css  js  c++  java
  • 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) 串的题,都可以尝试按位考虑

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

  • 相关阅读:
    Cocos2d-x 3.0 屏幕触摸及消息分发机制
    stretchableImageWithLeftCapWidth气泡拉伸
    海量数据插入数据库效率对照測试 ---ADO.NET下SqlBulkCopy()对照LINQ 下InsertAllOnSubmit()
    银联+移动+三星PK微信、余额宝
    热力学三大定律与熵
    热力学三大定律与熵
    OpenGL(六) gluLookAt和gluPerspective函数解析
    特殊字符
    特殊字符
    函数的功能
  • 原文地址:https://www.cnblogs.com/wawawa8/p/10162869.html
Copyright © 2011-2022 走看看