zoukankan      html  css  js  c++  java
  • hdu6155

    hdu6155

    题意

    给出一个只由 (01) 组成的字符串 (s),有两种操作:

    1. 翻转区间 ([l, r])
    2. 查询区间 ([l, r]) 有多少不同的子串

    分析

    首先考虑怎么统计区间有多少不同的子串。
    (dp[i][0]) 表示以 (s[i]=0) 结尾的字符串的个数,(dp[i][1]) 同理。
    (s[i]=0),有状态转移方程:(dp[i + 1][0] = dp[i][0] + dp[i][1] + 1)(dp[i+1][1]=dp[i][1])
    (dp[i][1]) 同理。
    那么答案就是 (dp[len][0]+dp[len][1])

    可以用矩阵递推:

    [egin{bmatrix} dp[i][0] & dp[i][1] & 1 end{bmatrix} * egin{bmatrix} 1 & 0 & 0\ 1 & 1 & 0\ 1 & 0 & 1 end{bmatrix} = egin{bmatrix} dp[i + 1][0] & dp[i + 1][1] & 1 end{bmatrix} ]

    又矩阵存在结合律,所以一段区间的查询,只需要求右边一系列乘数的乘积即可。
    我们可以使用线段树,去区间求积。

    对于翻转操作,先将第一列和第二列交换,再将第一行和第二行交换。因为 (01) 是相对的,只需要交换对应的值即可。

    可以在线段树中标记是否需要翻转某个区间。

    看完题解写完后,猛然发现,这竟是一道线段树区间更新区间求和的“模板题”。

    code

    #include<bits/stdc++.h>
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    using namespace std;
    typedef long long ll;
    const int MAXN = 1e5 + 10;
    const int MOD = 1e9 + 7;
    struct Matrix {
        ll mat[3][3];
        void init() {
            memset(mat, 0, sizeof mat);
        }
        Matrix operator *(Matrix A) {
            Matrix B;
            B.init();
            for(int i = 0; i < 3; i++) {
                for(int j = 0; j < 3; j++) {
                    for(int k = 0; k < 3; k++) {
                        B.mat[i][j] += mat[i][k] * A.mat[k][j];
                    }
                    B.mat[i][j] %= MOD;
                }
            }
            return B;
        }
    };
    char s[MAXN];
    int flip[MAXN << 2];
    Matrix sum[MAXN << 2];
    inline void magic(Matrix& A) { // 先将第一列和第二列交换,再将第一行和第二行交换
        for(int i = 0; i < 3; i++) swap(A.mat[i][0], A.mat[i][1]);
        for(int i = 0; i < 2; i++) swap(A.mat[0][i], A.mat[1][i]);
    }
    inline void pushUp(int rt) {
        sum[rt] = sum[rt << 1] * sum[rt << 1 | 1];
    }
    inline void pushDown(int rt) {
        if(flip[rt]) {
            flip[rt << 1] ^= flip[rt];
            flip[rt << 1 | 1] ^= flip[rt];
            magic(sum[rt << 1]);
            magic(sum[rt << 1 | 1]);
            flip[rt] = 0;
        }
    }
    void build(int l, int r, int rt) {
        flip[rt] = 0;
        if(l == r) {
            Matrix& A = sum[rt];
            if(s[l] == '0') {
                A = Matrix{1, 0, 0, 1, 1, 0, 1, 0, 1};
            } else {
                A = Matrix{1, 1, 0, 0, 1, 0, 0, 1, 1};
            }
            return;
        }
        int m = (l + r) / 2;
        build(lson);
        build(rson);
        pushUp(rt);
    }
    void update(int L, int R, int l, int r, int rt) {
        if(L <= l && r <= R) {
            flip[rt] ^= 1;
            magic(sum[rt]);
            return;
        }
        pushDown(rt);
        int m = (l + r) / 2;
        if(L <= m) update(L, R, lson);
        if(R > m) update(L, R, rson);
        pushUp(rt);
    }
    Matrix query(int L, int R, int l, int r, int rt) {
        if(L <= l && r <= R) {
            return sum[rt];
        }
        pushDown(rt);
        int m = (l + r) / 2;
        Matrix A;
        A.init();
        for(int i = 0; i < 3; i++) A.mat[i][i] = 1;
        if(L <= m) A = A * query(L, R, lson);
        if(R > m) A = A * query(L, R, rson);
        pushUp(rt);
        return A;
    }
    //适用于正整数
    template <class T>
    inline void scan_d(T &ret) {
        char c; ret=0;
        while((c=getchar())<'0'||c>'9');
        while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
    }
    int main() {
        int T;
        scanf("%d", &T);
        int n, q;
        while(T--) {
            scanf("%d%d", &n, &q);
            scanf("%s", s + 1);
            build(1, n, 1);
            while(q--) {
                int type, l, r;
                scan_d(type); scan_d(l); scan_d(r);
                if(type == 1) update(l, r, 1, n, 1);
                else {
                    Matrix A = query(l, r, 1, n, 1);
                    printf("%lld
    ", (A.mat[2][0] + A.mat[2][1]) % MOD);
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Python全栈开发之---mysql数据库
    python爬虫项目(scrapy-redis分布式爬取房天下租房信息)
    python多线程爬虫+批量下载斗图啦图片项目(关注、持续更新)
    python爬虫+数据可视化项目(关注、持续更新)
    超融合基本架构简单定义
    开启新生之路,,,学习网络
    Redhat7.2 ----team网卡绑定
    设计原则
    java应用程序的运行机制
    java三大版本和核心优势
  • 原文地址:https://www.cnblogs.com/ftae/p/7414139.html
Copyright © 2011-2022 走看看