码迷,mamicode.com
首页 > 其他好文 > 详细

uoj384 HNOI2018 寻宝游戏

时间:2018-05-03 22:06:21      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:一个   统计   需要   lin   code   efi   序列   +=   scan   

http://uoj.ac/problem/384

这道题有点厉害..

考虑 \(or\) \(and\) 运算的性质

如果在某一个位置\(and\)\(0\) 或者 \(or\)\(1\)

是不是前面的操作都白费了

于是按位考虑 压缩一下状态 以最右边的数作为最高位

设对于位\(i\)的状态是\(b_i\)

操作的序列同样压缩成\(op\)

\(or\)\(0\) \(and\)\(1\) (其实只需要建立一个\(and, or\)\(bit0, bit1\)的偏序关系就好了)

如果对于\(ans_i = 1\) 那么有\(b_i > op\)

同理对于\(ans_i = 0\) 那么有\(b_i \le op\)

统计答案的时候就是解若干个关于op的方程组

合并成\(l \le op < r\)的形式 那么\(result = r - l\)

解方程组的话可以先对\(\{b\}\)排序考虑第一次出现\(0,1\)位置

复杂度\(O((q + n) \times m)\)

#include <bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
  using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
  x = 0;char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
  for(int i = 1; i <= n; i ++)
    cout << a[i] << " ";
  puts("");
}
const int M = 5555;
const int mo = 1e9 + 7;
template<typename tp> inline int sub(tp a, tp b) {
  int ans = a - b; for(; ans < 0; ans += mo); return ans;
}
struct Node {
  vector<int> vec;
  int ha, id;
}a[M];
int n, m, q;
int r[M], rnk[M], pw[M];
char str[M];
inline bool cmp(const Node &a, const Node &b) {
  for(int k = n - 1; k >= 0; k --)
    if(a.vec[k] != b.vec[k])
      return a.vec[k] < b.vec[k];
  return a.id < b.id;    
}
main(void) {
  read(n); read(m); read(q);
  pw[0] = 1;
  for(int i = 1; i <= n; i ++)
    pw[i] = pw[i - 1] * 2 % mo;
  for(int i = 1; i <= n; i ++) {
    scanf("%s", str + 1);
    for(int k = 1; k <= m; k ++)
      a[k].vec.push_back(str[k] - '0');
  }
  for(int i = 1; i <= m; i ++) {
    int ha = 0;
    for(int k = n - 1; k >= 0; k --)
      ha = (ha * 2 + a[i].vec[k]) % mo;
    a[i].ha = ha; a[i].id = i;
  }
  sort(a + 1, a + m + 1, cmp); reverse(a + 1, a + m + 1);
  for(int k = 1; k <= m; k ++) rnk[a[k].id] = k;
  for(int i = 1; i <= q; i ++) {
    scanf("%s", str + 1);
    for(int k = 1; k <= m; k ++)
      r[rnk[k]] = str[k] - '0';
    int last1 = -1, first0 = m + 1;
    for(int k = 1; k <= m; k ++)
      if(r[k] == 0) {
        first0 = k;
        break;
      }
    for(int k = m; k >= 1; k --)
      if(r[k] == 1) {
        last1 = k;
        break;
      }
    if(first0 < last1) puts("0");
    else {
      if(last1 == -1) cout << sub(pw[n], a[first0].ha) << "\n";
      else cout << sub(a[last1].ha, a[last1 + 1].ha) << "\n";
    }
  }
}

uoj384 HNOI2018 寻宝游戏

标签:一个   统计   需要   lin   code   efi   序列   +=   scan   

原文地址:https://www.cnblogs.com/foreverpiano/p/8987475.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!