题目链接

题目

题目描述

I used to believe

We were burning on the edge of something beautiful

Something beautiful

Selling a dream

Smoke and mirrors keep us waiting on a miracle

On a miracle

Say go through the darkest of days

Heaven's a heartbreak away

Never let you go

Never let me down

OH it's been a hell of a ride

Driving the edge of a knife

Never let you go

Never let me down

Bieber拥有一个长度为n的01 串,他每次会选出这个串的一个子串作为曲谱唱歌,考虑该子串从左往右读所组成的二进制数P。 Bieber每一秒歌唱可以让P增加或减少 2 的 k次方(k由Bieber选定),但必须保证任意时刻其P大于等于0。

Bieber 是一位追求效率的人 每次Bieber都想知道他歌唱的最少时间将这个数P变成0。

Bieber 正和 一位DJ合作,他随时可能修改串上的一个字符。

输入描述

第一行一个数n

第二行一个长度为n的字符串s

第三行一个数 t 表示 询问 + 修改总次数

以下 t 行, 每行格式如下

第一个数 1 <= type <= 2 表示 类型

Type = 1 表示是一次 询问 接下来两个数 l , r 表示询问的区间。

否则 表示一次修改 接下来两个数x,y 表示把 s[x] 改为y.

n <= 3e5, t <= 3e5

输出描述

对于每个询问输出一个数表示最少次数。

示例1

输入

4
1101
1
1 1 4

输出

3

题解

知识点:动态dp,区间dp,线段树。

先考虑不带修改操作只有询问,那就是一道简单的区间dp题,复杂度是 \(O(n^3) \sim O(1)\) 。当然如果只询问 \([1,n]\) ,那就是线性dp了,复杂度 \(O(n)\)。

设 \(f_{l,r,i,j}\) 代表考虑区间 \([l,r]\) ,左端点状态为 \(i(0/1)\) (是否向高位进位),右端点状态为 \(j(0/1)\) (是否从低位进位)时的操作次数最小值。

显然,两个区间合并成一个区间时,分割点位置是无后效性的。因为根据现有的状态,一个子区间状态的答案以及方案和包含它的区间的状态没有任何关系,可以推得无论分割点在哪,答案是固定的。

因此,状态转移方程为:

\[\begin{aligned}
f_{l,r,i,j} = \min(f_{l,mid,i,0} + f_{mid+1,r,0,j},f_{l,mid,i,1} + f_{mid+1,r,1,j})
\end{aligned}
\]

其中 \(mid\) 从 \([l,r]\) 任选一点即可。

但是现在要求能够修改,那就必须使用线段树维护区间的dp信息了,也就是动态dp,每个线段树区间 \([l,r]\) 维护一个矩阵 \(f[0/1][0/1]\) 即可。维护信息的过程是十分显然的,因为此区间dp和分割点无关,就直接按照线段树的修改合并查询就做完了。

另外,区间信息的单位元值不好找,可以直接合并时特判,或者合并前排除无效区间,都可以的。

时间复杂度 \(O((n+m)\log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; struct T {
array<array<int, 2>, 2> f = { (int)1e9,(int)1e9,(int)1e9,(int)1e9 };
friend T operator+(const T &a, const T &b) {
// 这里用特殊值判断无效区间
// 当然,也可以在递归的时候直接避免掉无效区间,而不是在合并时才判断
if (a.f[0][0] == 1e9) return b;
if (b.f[0][0] == 1e9) return a;
auto x = T();
//* 广义矩阵乘法(乘改加,加改取最大值)
for (auto i : { 0,1 })
for (auto j : { 0,1 })
for (auto k : { 0,1 })
x.f[i][j] = min(x.f[i][j], a.f[i][k] + b.f[k][j]);
return x;
}
}; struct F {
bool upd;
T operator()(const T &x) {
return{
upd,1,
1,!upd
};
}
}; template<class T, class F>
class SegmentTree {
int n;
vector<T> node; void update(int rt, int l, int r, int x, F f) {
if (r < x || x < l) return;
if (l == r) return node[rt] = f(node[rt]), void();
int mid = l + r >> 1;
update(rt << 1, l, mid, x, f);
update(rt << 1 | 1, mid + 1, r, x, f);
node[rt] = node[rt << 1] + node[rt << 1 | 1];
} T query(int rt, int l, int r, int x, int y) {
if (r < x || y < l) return T();
if (x <= l && r <= y) return node[rt];
int mid = l + r >> 1;
return query(rt << 1, l, mid, x, y) + query(rt << 1 | 1, mid + 1, r, x, y);
} public:
SegmentTree(int _n = 0) { init(_n); }
SegmentTree(const vector<T> &src) { init(src); } void init(int _n) {
n = _n;
node.assign(n << 2, T());
}
void init(const vector<T> &src) {
assert(src.size() >= 2);
init(src.size() - 1);
function<void(int, int, int)> build = [&](int rt, int l, int r) {
if (l == r) return node[rt] = src[l], void();
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
node[rt] = node[rt << 1] + node[rt << 1 | 1];
};
build(1, 1, n);
} void update(int x, F f) { update(1, 1, n, x, f); } T query(int x, int y) { return query(1, 1, n, x, y); }
}; int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
vector<T> a(n + 1);
for (int i = 1;i <= n;i++) {
char x;
cin >> x;
a[i] = {
x == '1',1,
1,x != '1'
};
}
SegmentTree<T, F> sgt(a);
int m;
cin >> m;
while (m--) {
int op;
cin >> op;
if (op == 1) {
int l, r;
cin >> l >> r;
cout << sgt.query(l, r).f[0][0] << '\n';
}
else {
int x;
bool val;
cin >> x >> val;
sgt.update(x, { val });
}
}
return 0;
}

NC19469 01串的更多相关文章

  1. JZOJ P1847:找01串

    传送门 DP预处理+贪心 首先设$f[i][j]$表示长度为$i$的01串中有不大于$j$个1,然后显然 $f[i][j]=\sum_{k=1} ^{j} C[i][k]$ $C[i][j]=C[i- ...

  2. 洛谷P2727 01串 Stringsobits

    P2727 01串 Stringsobits 24通过 55提交 题目提供者该用户不存在 标签USACO 难度普及+/提高 提交  讨论  题解 最新讨论 这题的思路是啥啊!!!跪求- 题目背景 考虑 ...

  3. C++实现01串排序

    题目内容:将01串首先按长度排序,长度相同时,按1的个数从少到多进行排序,1的个数相同时再按ASCII码值排序. 输入描述:输入数据中含有一些01串,01串的长度不大于256个字符. 输出描述:重新排 ...

  4. 01串(dp)

    01串 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有“11”子串的这种长度的01串共有多少个, ...

  5. 【巧妙】【3-21个人赛】Problem C 01串

    Problem C Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Sub ...

  6. NYOJ-252 01串

    01串 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描写叙述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有"11"子串的这样的长 ...

  7. NYOJ 252 01串(斐波那契数列变形)

    01串 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有“11”子串的这种长度的01串共有多少个, ...

  8. COGS 862. 二进制数01串【dp+经典二分+字符串】

    862. 二进制数01串 ★   输入文件:kimbits.in   输出文件:kimbits.out   简单对比 时间限制:1 s   内存限制:128 MB USACO/kimbits(译 by ...

  9. 1415: 小ho的01串 [字符串]

    点击打开链接 1415: 小ho的01串 [字符串] 题目描述 有一个由0和1组成的字符串,它好长呀--------一望无际 恩,说正题,小ho的数学不太好,虽然是学计算机的但是看见0和1也是很头疼的 ...

  10. bitset(01串)优化

    bitset的经典使用: 见代码及注释: #include<bitset> #include<algorithm> using namespace std; //只需调用< ...

随机推荐

  1. IDEA比较常用的快捷键

    IDEA比较常用的快捷键 快捷键 说明 Ctrl+] 诸如{}围起来的代码块,使用该快捷键可以快速跳转至代码块的结尾处 Ctrl+[ 同上,快速跳至代码块的开始出 Ctrl+Shift+Enter 将 ...

  2. js指南

    1.for /in: 与for/of相比,可迭代对象不同,in后面可以是任意对象.数组.字符串.集合和映射可迭代. object.keys()   object.values()   object.e ...

  3. MQ:Communications link failure

    ActiveMQ:Communications link failure问题以及解决办法   ActiveMQ版本:5.5.1 MQ 所使用的 MySQL 是 InnoDB存储引擎 记录人:@郑昀 现 ...

  4. 记一下Linux环境SpringBoot 用OpenOffice Word转PDF

    环境 Windows或者Linux 首先安装 deb方式 tar -xvzf Apache_OpenOffice_XXXX_Linux_x86-64_install-deb_zh-CN.tar.gz ...

  5. Apache和Nginx有什么区别,如何选择?

    Apache和Nginx都是大名鼎鼎的Web服务器软件. 网上已经有非常多关于apache和nginx区别的文章了,笔者就不从专业技术的角度进行解说,而按照目前比较流行的架构方式进行阐述. 1.安全性 ...

  6. Scanner进阶使用

    Scanner 进阶使用 package com.andy.base.scanner; import java.util.Scanner; public class Demo04 { public s ...

  7. 在教学中常被问到的几个vue3.x与typescript的问题,统一解答

    在教学当中,学生在学习vue3.x时,常常会问到typescript和vue3.x之间的关系,感觉这两个技术总是绑在一起的,下面老赵来统一解答一下: 那学vue3.x,为什么要求也要掌握typescr ...

  8. 11.8 消除闪烁(2)(harib08h)

    ps:看书比较急,有错误的地方欢迎指正,不细致的地方我会持续的修改 11.8 消除闪烁(2)(harib08h) 11.7 消除闪烁(1)(harib08g)存在的问题: 鼠标放在计时器上会有 闪烁, ...

  9. ZOJ 3735 Josephina and RPG (概率dp)

    题意:给你一个n,然后给你C(n,3)个队伍, 给你每个队伍之间的胜率. 接下来给你m个队伍,让你依次跟他们比赛,开始你能选择任意的队伍,如果你打赢了一支队伍,你可以选择换成输给你的这个队伍或者不换, ...

  10. Hello, YOU -- 通过简单的 hello_test.go 程序理解并学会编写测试

    Hello, YOU 书接上文上篇文章中,我们尝试编写了hello word 函数以及第一个测试 hello_test package main import "fmt" func ...