NC19469 01串

这篇具有很好参考价值的文章主要介绍了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)\) (是否从低位进位)时的操作次数最小值。

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

因此,状态转移方程为:

\[\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)\)文章来源地址https://www.toymoban.com/news/detail-431998.html

代码

#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串的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 长春理工大学第六届CTF网络攻防大赛题解(文末有题目下载链接)

    此题解仅为部分题解,包括: 【RE】:①Reverse_Checkin ②SimplePE ③EzGame 【Web】①f12 ②ezrunner 【Crypto】①MD5 ②password ③看我回旋踢 ④摩丝 【Misc】①爆爆爆爆 ②凯撒大帝的三个秘密 ③你才是职业选手 ① Reverse Checkin: 双击文件看到如上提示:“也许你能从字符串里找到什么”

    2024年02月05日
    浏览(66)
  • 微信分享第三方连接(H5页面)自定义缩略图、标题、描述(显示分享框,而不是链接)(微信JS-SDK)

    首先要说明几个分享相关的问题: 现在微信不支持自定义按钮分享组件(也就是说不能点击某个按钮分享),只能通过微信右上角的三个小点,点击后选择分享给朋友,朋友圈等。 当前从企业微信分享到微信好友和微信朋友圈是有问题的,一些手机(有些是因为app版本,企

    2024年02月09日
    浏览(53)
  • 【LeetCode题目详解】1281题 整数的各位积和之差 面试题 01.01. 判定字符是否唯一 python题解(作业一二)

    问题描述: 1281. 整数的各位积和之差 给你一个整数 n,请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。 示例 1: 输入:n = 234 输出:15 解释: 各位数之积 = 2 * 3 * 4 = 24 各位数之和 = 2 + 3 + 4 = 9 结果 = 24 - 9 = 15 示例 2: 输入:n = 4421 输出:21 解释:

    2024年02月10日
    浏览(50)
  • 【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析

    动态规划就像是解决问题的一种策略,它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题,并将每个小问题的解保存起来。这样,当我们需要解决原始问题的时候,我们就可以直接利用已经计算好的小问题的解,而不需要重

    2024年02月03日
    浏览(45)
  • 英伟达H800服务器安装ubuntu2204及使用gpu-burn压测

    安装Ubuntu 22.04 LTS 镜像:ubuntu-22.04.3-live-server-amd64.iso 可以使用两种方式安装: 通过BMC直接挂载ISO,在BIOS里调整顺序 可通过rufus等usb烧录软件,将ISO烧到USB启动盘中,此种方式安装会更快些。 安装系统时选择默认设置,建议选择server安装模式,建议选择安装docker程序。 更新内

    2024年02月20日
    浏览(57)
  • 【LeetCode题目详解】第九章 动态规划part01 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯 (day38补)

    斐波那契数  (通常用  F(n) 表示)形成的序列称为 斐波那契数列 。该数列由  0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: 给定  n ,请计算 F(n) 。 示例 1: 示例 2: 示例 3: 提示: 0 = n = 30 斐波那契数列大家应该非常熟悉不过了,非常适合作为动规第

    2024年02月07日
    浏览(47)
  • 玩客云Armbian_23.08.0-trunk_Onecloud_bookworm_edge_6.4.14.burn配置

    固定IP dhcp 加证书 改源 装docker

    2024年02月08日
    浏览(40)
  • NC200204 数位 DP

    题意 传送门 NC200204 dh的帽子 题解 可以独立考虑每一位是否合法。维护数字上下界的状态,枚举三个数字,仅对合法的状态进行转移。数位 DP 求解即可,时间复杂度 O ( l o g R ) O(logR) O ( l o g R ) 。

    2024年02月16日
    浏览(41)
  • Netcat安装与使用(nc)

      Netcat 是一款简单的Unix工具,使用UDP和TCP协议,被称为网络工具中的\\\"瑞士军*刀\\\"。它是一个可靠的容易被其他程序所启用的后台操作工具,同时它也被用作网络的测试工具或黑客工具。 使用它你可以轻易的建立任何连接。   在Linux中都是自带Netcat的,如果没有,可以使

    2023年04月22日
    浏览(35)
  • ArcGIS处理nc数据步骤

    使用ArcGIS读取nc文件步骤: 1.打开ArcGIS,在多维工具下选择“创建NetCDF栅格图层” 2.输入nc文件,其他参数可忽略,点击确定 3.创建好后,右键点击图层,点击属性,选择“NetCDF”,然后选择波段纬度,接着点击纬度对应的值,这里维度值对应的是时间,选择任意一个时间。

    2024年02月15日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包