NC19469 01串
题目
题目描述
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)\) (是否从低位进位)时的操作次数最小值。
显然,两个区间合并成一个区间时,分割点位置是无后效性的。因为根据现有的状态,一个子区间状态的答案以及方案和包含它的区间的状态没有任何关系,可以推得无论分割点在哪,答案是固定的。
因此,状态转移方程为:
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串的更多相关文章
- 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- ...
- 洛谷P2727 01串 Stringsobits
P2727 01串 Stringsobits 24通过 55提交 题目提供者该用户不存在 标签USACO 难度普及+/提高 提交 讨论 题解 最新讨论 这题的思路是啥啊!!!跪求- 题目背景 考虑 ...
- C++实现01串排序
题目内容:将01串首先按长度排序,长度相同时,按1的个数从少到多进行排序,1的个数相同时再按ASCII码值排序. 输入描述:输入数据中含有一些01串,01串的长度不大于256个字符. 输出描述:重新排 ...
- 01串(dp)
01串 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有“11”子串的这种长度的01串共有多少个, ...
- 【巧妙】【3-21个人赛】Problem C 01串
Problem C Time Limit : 3000/1000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other) Total Sub ...
- NYOJ-252 01串
01串 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描写叙述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有"11"子串的这样的长 ...
- NYOJ 252 01串(斐波那契数列变形)
01串 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有“11”子串的这种长度的01串共有多少个, ...
- COGS 862. 二进制数01串【dp+经典二分+字符串】
862. 二进制数01串 ★ 输入文件:kimbits.in 输出文件:kimbits.out 简单对比 时间限制:1 s 内存限制:128 MB USACO/kimbits(译 by ...
- 1415: 小ho的01串 [字符串]
点击打开链接 1415: 小ho的01串 [字符串] 题目描述 有一个由0和1组成的字符串,它好长呀--------一望无际 恩,说正题,小ho的数学不太好,虽然是学计算机的但是看见0和1也是很头疼的 ...
- bitset(01串)优化
bitset的经典使用: 见代码及注释: #include<bitset> #include<algorithm> using namespace std; //只需调用< ...
随机推荐
- 后端004-JWT工具类的编写
登录功能采用springsecurity安全框架和jwt令牌 首先需要添加依赖信息 在yml中添加JWT的配置文件 有了上述的配置之后,我们可以准备一个JWT的工具类,方便后面和JWT相关的内容去使用 ...
- IDEA快键键设置为Eclipse快捷键
一.基础修改,参考这个就可以了 https://jingyan.baidu.com/article/6dad5075a5f7b4e122e36e4b.html 二.其他需要手动配置的快捷键修改(主要是 ...
- ZOJ 3735 Josephina and RPG (概率dp)
题意:给你一个n,然后给你C(n,3)个队伍, 给你每个队伍之间的胜率. 接下来给你m个队伍,让你依次跟他们比赛,开始你能选择任意的队伍,如果你打赢了一支队伍,你可以选择换成输给你的这个队伍或者不换, ...
- Linux 命令之 tar 操作符
tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个 ...
- 【分布式技术专题】「分布式技术架构」一文带你厘清分布式事务协议及分布式一致性协议的算法原理和核心流程机制(Paxos篇)
概念简介 Paxos是一种基于消息传递具有高度容错特性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一. 发展历史 Paxos算法的发展历史追溯到古希腊,当时有一个名为"Pax ...
- Spring MVC 和 Struts 的区别是什么?
1. 拦截机制的不同 Struts2 是类级别的拦截,每次请求就会创建一个 Action,和 Spring 整合时 Struts2 的 ActionBean 注入作用域是原型模式 prototype, ...
- CAS乐观锁(原子操作)
更多内容,前往 IT-BLOG 锁主要分为两种:乐观锁和悲观锁,而 synchronized 就属于一种悲观锁,每次在操作数据前都会加锁.乐观锁是指:乐观的认为自己在操作数据时,别人不会对当前数据进行 ...
- 单元测试Mockito框架
单元测试Mockito框架 Mock 测试就是在测试过程中,对于某些 不容易构造(如 HttpServletRequest 必须在 Servlet 容器中才能构造出来)或者不容易获取 比较复杂 的对象 ...
- centos7无网环境安装docker
1.下载docker的安装文件 https://download.docker.com/linux/static/stable/x86_64/ 由于公司OpenStack用的docker版本是18.0 ...
- CTF-RE-学习记录-汇编
八进制运算 加法表 1+1=2 1+2=3 2+2=4 1+3=4 2+3=5 3+3=6 1+4=5 2+4=6 3+4=7 4+4=10 1+5=6 2+5=7 3+5=8 4+5=11 5+5= ...