题意

给定两个长度为 \(n\) 的序列 \(\{a_i\}\) 与 \(\{b_i\}\),你需要求出它们的相似度。,我们定义这两个序列的相似度为将其中一个序列转化为另一个序列所需的最小操作次数。一次操作定义如下: - 选择序列中的一个长度为 \(k\) 的子段,将子段内的所有元素异或上一个相同的值 \(x\),\(x\) 可以任意决定。特殊地,若其中一个序列无论如何都不能转化到另一个序列,那么这两个序列的相似度为 \(-1\)。 这之后,将会有 \(q\) 次修改操作,单次操作格式如下:

s p v:\(s\) 是一个小写字符,且要么为 a,要么为 b。若 \(s =\) a,则表明将 \(a_p\) 的值修改为 \(v\);若 \(s =\) b,则表明将 \(b_p\) 的值修改为 \(v\)。

在每一次修改操作结束后,你也需要求出两个序列的相似度。输出最开始及每次修改后的答案。

\(1 \leq k \leq n \leq 2 \times 10^5, 0 \leq q \leq 2 \times 10^5, 1 \leq p \leq n, 0 \leq a_i, b_i, v < 2^{14}\),输入保证给出的两个序列长度均为 \(n\)。

分析

  • 先考虑暴力:每次暴力修改,然后贪心地从第一个位置开始推,要修改就修改。

  • 考虑差分,这样每次修改的位置就只有两个了。

  • 将所有位置按照模 \(k\) 分组,每一组互不干扰。我们记某组中连续的三个位置为 1,2,3,\(c\) 数组表示 \(a\) 和 \(b\) 的差分数组的异或结果。每个位置需要异或的值就是 \(c_1; c_1\ xor\ c_2;c_1\ xor\ c_2\ xor c_3\),所以如果有解,每组的异或值都要为0.

  • 讨论 \(k\) 的大小来修改:

    如果 \(k > \sqrt n\) ,每组个数 \(\frac{n}{k}<\sqrt n\) ,暴力即可, 复杂度 \(O(n\sqrt n)\)。

    如果 \(k<\sqrt n\) ,组数 \(k<\sqrt n\) ,每组分块维护,复杂度 \(O(n\sqrt n)\) 。

  • 总时间复杂度为 \(O(n\sqrt n)\)。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi() {
int x = 0,f = 1;
char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
return x * f;
}
template <typename T> inline void Max(T &a, T b){if(a < b) a = b;}
template <typename T> inline void Min(T &a, T b){if(a > b) a = b;}
const int N = 2e5 + 7, gg = 400;
int n, k, q, ans, cnt, ndc;
int a[N], b[N], c[N], pre[N], bl[N], L[N], tag[N];
char s[N];
int num[1007][17000];
void upd1(int p, int v) {
for(int i = p; i <= n; i += k) {
pre[i] ^= v;
if(v && pre[i] == 0) --ans;
if(v && pre[i] == v) ++ans;
}
int lst = p % k + ((n - p % k) / k) * k;
if(v && pre[lst] == 0) --cnt;
if(v && pre[lst] == v) ++cnt;
}
void upd2(int p, int v) {
for(int i = p; bl[i] == bl[p]; i += k) {
if(v && (pre[i] ^ tag[bl[p]]) == 0) ++ans;
num[bl[p]][pre[i]] --;
pre[i] ^= v;
num[bl[p]][pre[i]] ++;
if(v && (pre[i] ^ tag[bl[p]]) == 0) --ans;
}
for(int i = bl[p] + 1; i <= ndc && L[i] % k == p % k; ++i) {
if(v) ans += num[i][tag[i]];
tag[i] ^= v;
if(v) ans -= num[i][tag[i]];
}
int lst = p % k + ((n - p % k) / k) * k;
if(v && (pre[lst] ^ tag[bl[lst]]) == 0) --cnt;
if(v && (pre[lst] ^ tag[bl[lst]]) == v) ++cnt;
}
void modify(int p, int v) {
if(n / k < gg)
upd1(p, v ^ c[p]);
else
upd2(p, v ^ c[p]);
c[p] = v;
}
int main() {
n = gi(), k = gi(), q = gi();
rep(i, 1, n) a[i] = gi();
rep(i, 1, n) b[i] = gi();
++n; if(n / k >= gg)
for(int i = 1; i <= k; ++i)
for(int j = i; j <= n; j += k) {
if(((j - 1) / k + 1) % gg == 1) {
L[++ndc] = j;
num[ndc][0] = min(gg, (n - j) / k + 1);
}
bl[j] = ndc;
}
rep(i, 1, n) modify(i, (a[i] ^ a[i - 1]) ^ (b[i] ^ b[i - 1]));
printf("%d\n", cnt ? -1 : ans);
int i, v;
while(q--) {
scanf("%s%d%d", s, &i, &v);
if(s[0] == 'a') a[i] = v;
else b[i] = v;
modify(i, (a[i] ^ a[i - 1]) ^ (b[i] ^ b[i - 1]));
if(i != n) modify(i + 1, (a[i + 1] ^ a[i]) ^ (b[i + 1] ^ b[i]));
printf("%d\n", cnt ? -1 : ans);
}
return 0;
}

[CF1083F]The Fair Nut and Amusing Xor[差分+同余分类+根号分治+分块]的更多相关文章

  1. [cf1083F]The Fair Nut and Amusing Xor

    令$c_{i}=a_{i}\oplus b_{i}$,那么也就是要对$c_{i}$执行操作使其变为0 显然有一个贪心的策略,即从左往右,若当前$c_{i}\ne 0$,则执行对$[i,i+k)$异或$ ...

  2. CF1083E The Fair Nut and Rectangles

    CF1083E The Fair Nut and Rectangles 给定 \(n\) 个平面直角坐标系中左下角为坐标原点,右上角为 \((x_i,\ y_i)\) 的互不包含的矩形,每一个矩形拥有 ...

  3. CF 1083 B. The Fair Nut and Strings

    B. The Fair Nut and Strings 题目链接 题意: 在给定的字符串a和字符串b中找到最多k个字符串,使得不同的前缀字符串的数量最多. 分析:  建出trie树,给定的两个字符串就 ...

  4. CF 1083 A. The Fair Nut and the Best Path

    A. The Fair Nut and the Best Path https://codeforces.com/contest/1083/problem/A 题意: 在一棵树内找一条路径,使得从起点 ...

  5. CF1083A The Fair Nut and the Best Path

    CF1083A The Fair Nut and the Best Path 先把边权搞成点权(其实也可以不用),那么就是询问树上路径的最大权值. 任意时刻权值非负的限制可以不用管,因为若走路径 \( ...

  6. Codeforces Round #526 (Div. 2) E. The Fair Nut and Strings

    E. The Fair Nut and Strings 题目链接:https://codeforces.com/contest/1084/problem/E 题意: 输入n,k,k代表一共有长度为n的 ...

  7. Codeforces Round #526 (Div. 2) D. The Fair Nut and the Best Path

    D. The Fair Nut and the Best Path 题目链接:https://codeforces.com/contest/1084/problem/D 题意: 给出一棵树,走不重复的 ...

  8. Codeforces Round #526 (Div. 2) C. The Fair Nut and String

    C. The Fair Nut and String 题目链接:https://codeforces.com/contest/1084/problem/C 题意: 给出一个字符串,找出都为a的子序列( ...

  9. C. The Fair Nut and String 递推分段形dp

    C. The Fair Nut and String 递推分段形dp 题意 给出一个字符串选择一个序列\({p_1,p_2...p_k}\)使得 对于任意一个\(p_i\) , \(s[p_i]==a ...

随机推荐

  1. 无线网卡加密方式wep wpa/wpa2 介绍

    常见无线热点的配置选项:无线名称路由器的无线(Wi-Fi)名称.无线密码无线加密使用WPA2-PSK/WPA-PSK加密方式.AES加密算法,无线密码为8-63个字符,最好是数字.字母.符号的组合.信 ...

  2. [CentOS7] [VMWARE] 增加磁盘空间后扩大逻辑分区

    Learn to rescan disk in Linux VM when its backed vdisk in vmware is extended. This method does not r ...

  3. jboss eap6.1(1)

    最近决定把公司的项目从jboss3.x迁移出来,先试着摸索一下最新的jboss服务器,从jboss官网上下了一份jboss-eap-6.1,然后找资料准备学习,同时将此次迁移过程记录下来,以备后续复习 ...

  4. 【redis】redis的雪崩和穿透

    1.什么是缓存穿透 一般的缓存系统,都是按照key值去缓存查询,如果不存在对应的value,就应该去DB中查找 .这个时候,如果请求的并发量很大,就会对后端的DB系统造成很大的压力.这就叫做缓存穿透. ...

  5. mysql数据库管理工具(navicat for mysql) 10.1.7 绿色中文版

    Navicat for MySQL:Navicat for MySQL 是一套专为 MySQL 设计的高性能数据库管理及开发工具.它可以用于任何版本 3.21 或以上的 MySQL 数据库服务器,并支 ...

  6. arrayfun用法(转)

    http://blog.sina.com.cn/s/blog_7cf4f4460101bnhh.html 利用arrayfun函数可以避免无谓的循环,从而大大提高代码的简介性.1.A=ARRAYFUN ...

  7. arm 开发板更新 gcc/gcc++ | Debain 更新 gcc,无需编译直接更新 gcc

    4我的板子是 Orange pi 3,只能以 卧槽来形容... 我是搞.net core的,这板子死活搞不了. 刷的是Debain系统. 说实话,这个板子不错,可就是官方的系统实在不敢恭维,内核旧,软 ...

  8. 复合梯形公式、复合辛普森公式 matlab

    1. 用1阶至4阶Newton-Cotes公式计算积分 程序: function I = NewtonCotes(f,a,b,type) % syms t; t=findsym(sym(f)); I= ...

  9. PyQt5--QProgressBar

    # -*- coding:utf-8 -*- ''' Created on Sep 20, 2018 @author: SaShuangYiBing Comment: ''' import sys f ...

  10. 面向对象的JavaScript --- 动态类型语言

    面向对象的JavaScript --- 动态类型语言 动态类型语言与面向接口编程 JavaScript 没有提供传统面向对象语言中的类式继承,而是通过原型委托的方式来实现对象与对象之间的继承. Jav ...