LOJ6500. 「雅礼集训 2018 Day2」操作(哈希+差分)
题目链接
题解
区间取反 \(01\) 串的经典套路是差分。我们令 \(b_i = a_i\ {\rm xor}\ a_{i - 1}\)(\(\{a_i\}\) 表示原 \(01\) 序列),这样每一次对一个长度为 \(k\) 的区间取反只会使两个 \(b_i\) 发生变化,不妨设为 \(b_x, b_y(x < y)\),那么一定满足 \(y - x = k\)。而我们的目的就是使得差分后数组 \(b\) 里的所有 \(1\) 变为 \(0\)。
为了方便,接下来的分析均只使用差分后的数组 \(b\)。
首先很显然的是,模 \(k\) 后值不同的位置绝不会互相影响。因此我们可以将所有位置 \(i\) 按照模 \(k\) 的值分组,模 \(k\) 的值相同的位置属于同一组。那么对于每次询问,有解当且仅当 \(b\) 数组的每一组在区间 \([l, r + 1]\) (由于是差分数组,因此要考虑位置 \(r + 1\))内都恰好包含偶数个 \(1\)。奇偶性的判断通常用哈希完成,具体地,我们可以给同一组内所有满足 \(b_i = 1\) 的位置 \(i\) 赋一个相同的较大的随机值,不同的组赋不同的值,那么一段区间有解,一定满足区间内所有值的异或和为 \(0\)。这样,我们就能够在 \(O(1)\) 的时间内判断区间是否有解。
接下来考虑如何计算最小操作次数。对于任意的 \(j(0 \leq j < k)\),假设满足 \(b_i = 1\) 且 \(i\ {\rm mod}\ k = j\) 的所有位置 \(i\) 从小到大分别为 \(p_1, p_2, \cdots, p_{2t - 1}, p_{2t}\),那么考虑贪心,我们肯定是从左至右依次选择最近的两个 \(p\) 消去,因此答案为 \(\frac{(p_2 - p_1) + (p_4 - p_3) + \cdots + (p_{2t} - p_{2t - 1})}{k}\)。我们可以设法维护这个式子的前缀和。在从左至右依次处理时,由于每一组内从右至左的第奇数个已处理的满足 \(b_i = 1\) 的 \(i\) 有正的贡献,第偶数个已处理的满足 \(b_i = 1\) 的 \(i\) 有负的贡献,而新的 \(i\) 加入会导致奇偶性改变,即会发生正负交替,因此每加入一个 \(b_i = 1\) 的 \(i\) 时,我们直接将 \(i\ {\rm mod}\ k\) 的所有位置的贡献和取反再加上 \(i\),最后再添加到前缀和中即可。
最后注意由于每次询问 \([l, r]\) 时我们要强制使得 \(a_{l - 1} = a_{r + 1} = 0\),因此区间的边界需要特殊处理。
这样,我们就在 \(O(n + m)\) 的时间内解决了此题。
代码
#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long ll;
typedef long double ld;
typedef unsigned int uint;
typedef pair<int, int> pii;
typedef unsigned long long ull;
template<typename T> inline void read(T& x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}
template<typename T, typename... U> inline void read(T& x, U&... y) {
  read(x), read(y...);
}
template<typename T> inline bool checkMax(T& a, const T& b) {
  return a < b ? a = b, true : false;
}
template<typename T> inline bool checkMin(T& a, const T& b) {
  return a > b ? a = b, true : false;
}
const int N = 2e6 + 10;
int n, k, m, s[N][3], v[N];
char str[N];
ull hash_val[N], pre[N];
inline ull get_random() {
  return (1ull * rand() << 30) + (1ull * rand() << 15) + rand();
}
int main() {
  read(n, k, m);
  scanf("%s", str + 1), str[0] = '0';
  for (register int i = 0; i < k; ++i) {
    hash_val[i] = get_random();
  }
  for (register int i = 1; i <= n; ++i) {
    if (str[i] ^ str[i - 1]) {
      pre[i] = pre[i - 1] ^ hash_val[i % k];
      s[i][0] = s[i - 1][0] + i - (v[i % k] << 1);
      v[i % k] = i - v[i % k];
    } else {
      pre[i] = pre[i - 1];
      s[i][0] = s[i - 1][0];
    }
    s[i][1] = v[i % k];
    s[i][2] = v[(i + 1) % k];
  }
  for (register int i = 1; i <= m; ++i) {
    int l, r; read(l, r);
    ull t = pre[r] ^ pre[l];
    int res = s[r][0] - s[l][0];
    if (str[l] == '1') {
      t ^= hash_val[l % k];
      res -= l - (s[l][1] << 1);
    }
    if (str[r] == '1') {
      t ^= hash_val[(r + 1) % k];
      res += r + 1 - (s[r][2] << 1);
    }
    printf("%d\n", !t ? res / k : -1);
  }
  return 0;
}
												
											LOJ6500. 「雅礼集训 2018 Day2」操作(哈希+差分)的更多相关文章
- 「LOJ #6500」「雅礼集训 2018 Day2」操作
		
description LOJ 6500 solution 根据常有套路,容易想到将区间差分转化为异或数组上的单点修改,即令\(b_i=a_i \ xor\ a_{i-1}\), 那么将\([l,l+ ...
 - 「雅礼集训 2018 Day2」农民
		
传送门 Description 「搞 OI 不如种田.」 小 D 在家种了一棵二叉树,第 ii 个结点的权值为 \(a_i\). 小 D 为自己种的树买了肥料,每天给树施肥. 可是几天后,小 D 却 ...
 - 【卡常  bitset  分块】loj#6499. 「雅礼集训 2018 Day2」颜色
		
好不容易算着块大小,裸的分块才能过随机极限数据:然而这题在线的数据都竟然是构造的…… 题目描述 有 $n$ 个数字,第 $i$ 个数字为 $a_i$. 有 $m$ 次询问,每次给出 $k_i$ 个区间 ...
 - #6499. 「雅礼集训 2018 Day2」颜色 [分块,倍增,bitset]
		
bitset压位,因为是颜色数,直接倍增,重合部分不管,没了. // powered by c++11 // by Isaunoya #include <bits/stdc++.h> #d ...
 - 【LOJ6498】「雅礼集训 2018 Day2」农民
		
题面 solution 直接暴力模拟,原数据可获得满分的成绩. 对于每个点,其父亲对其都有一个限制.故我们只需要判断当前点到根的路径上的限制是否都能满足即可. 考虑用树剖+线段树维护这个限制.考虑到翻 ...
 - 「雅礼集训 2017 Day2」解题报告
		
「雅礼集训 2017 Day2」水箱 我怎么知道这种题目都能构造树形结构. 根据高度构造一棵树,在树上倍增找到最大的小于约束条件高度的隔板,开一个 \(vector\) 记录一下,然后对于每个 \(v ...
 - #6034. 「雅礼集训 2017 Day2」线段游戏   李超树
		
#6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统 ...
 - 【loj6034】「雅礼集训 2017 Day2」线段游戏
		
#6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:Special Judge 上传者: 匿名 题目描述 ...
 - Loj #6503. 「雅礼集训 2018 Day4」Magic
		
Loj #6503. 「雅礼集训 2018 Day4」Magic 题目描述 前进!前进!不择手段地前进!--托马斯 · 维德 魔法纪元元年. 1453 年 5 月 3 日 16 时,高维碎片接触地球. ...
 
随机推荐
- 约瑟夫问题的变种 LA3882
			
题目大意: N个数排成一圈,第一次删除m,以后每k个数删除一次,求最后一被删除的数. 如果这题用链表或者数组模拟整个过程的话,时间复杂度都将高达O(nk),而n<=10000,k<=100 ...
 - python准确判断文件类型
			
判断文件类型在开发中非常常见的需求,怎样才能准确的判断文件类型呢?首先大家想到的是文件的后缀,但是非常遗憾的是这种方法是非常不靠谱的,因为文件的后缀是可以随意更改的,而大家都知道后缀在linux系统下 ...
 - smarty类与对象的赋值与使用
			
<?phprequire_once('../smarty/Smarty.class.php'); //配置信息$smarty=new Smarty(); $smarty->left_del ...
 - Caused by: org.hibernate.HibernateException: Unable to build the default ValidatorFactory
			
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testAction': ...
 - linux 分区 文件系统
			
操作系统通过文件系统管理文件及数据,磁盘或分区需要创建文件系统之后才能为操作系统使用,创建文件系统的过程又称之为格式化. 没有文件系统的设备称之为裸设备(raw); 常见的文件系统有fat32,NTF ...
 - delphi7列宽自定设置为固定值
 - static 静态类
			
C# 编译器对静态类进行了如下限制. 1. 静态类必须直接从System.Object派生,从其他任何基类生都没有意义,继承只适用于对象,而你不能创建静态类的实例. 2. 静态类不能实现任何接口,这是 ...
 - [LeetCode 题解]: Minimum Depth of Binary Tree
			
Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...
 - Android View与ViewGroup 关系
			
View派生出的直接子类有:AnalogClock,ImageView,KeyboardView, ProgressBar,SurfaceView,TextView,ViewGroup,ViewStu ...
 - [Asp.net Mvc]为js,css静态文件添加版本号
			
方式一: 思路 string version = ViewBag.Version; @Scripts.RenderFormat("<script type=\"text/ja ...