• ccpc 网络赛 hdu 6155


    # ccpc 网络赛 hdu 6155(矩阵乘法 + 线段树)

    题意:

    给出 01 串,要么询问某个区间内不同的 01 子序列数量,要么把区间翻转。

    叉姐的题解:

    先考虑怎么算 (s_1, s_2, ldots, s_n)的答案。
    (dp(i, 0/1)) 表示考虑到 (s_i)
    ,以 (0/1) 结尾的串的数量。
    那么 (dp(i, 0) =dp(i - 1, 0) + dp(i - 1, 1) + 1)(1)也同理。
    那么假设在某个区间之前,(dp(i, 0/1) = (x, y)) 的话,过了这段区间,就会变成 ((ax + by + c, dx + ey + f)(ax+by+c,dx+ey+f)) 的形式,只要用线段树维护这个线性变化就好了。


    fzu 2129 子序列的个数 做过这道题的话 dp方程应该写的出来

    一直在思考如何区间合并这个东西,或者区间是否具有加减性质,可以的话就可以用线段树做了,然而并不能

    维护矩阵真的是涨姿势了
    先列出转移矩阵把

    如果(s_i = 0),则有
    (dp[i][0] = 1 * dp[i-1][0] + 1 * dp[i-1][1] + 1 * 1)
    (dp[i][1] = 0 * dp[i-1][0] + 1 * dp[i-1][1] + 0 * 1)
    否则
    (dp[i][0] = 1 * dp[i-1][0] + 0 * dp[i-1][1] + 0 * 1)
    (dp[i][1] = 1 * dp[i-1][0] + 1 * dp[i-1][1] + 1 * 1)

    初始化(dp[0][0/1] = 0)
    初始矩阵就为
    (egin{bmatrix} 0\ 0\ 1 end{bmatrix})
    如果当前为0,矩阵是这样的
    (egin{bmatrix} 1& 1 & 1\ 0& 1 & 0\ 0& 0 & 1 end{bmatrix})
    否则就是这样的
    (egin{bmatrix} 1& 0 & 0\ 0& 1 & 1\ 0& 0 & 1 end{bmatrix})

    假设当前字符串为01,那么最后矩阵就是
    (egin{bmatrix} 1& 0 & 0\ 0& 1 & 1\ 0& 0 & 1 end{bmatrix} cdot egin{bmatrix} 1& 1 & 1\ 0& 1 & 0\ 0& 0 & 1 end{bmatrix} cdot egin{bmatrix} 0\ 0\ 1 end{bmatrix} = egin{bmatrix} 1\ 2\ 1 end{bmatrix})

    通过1和0的转移矩阵容易知道区间翻转其实就是把矩阵的某些元素交换一下

    然后写个线段树区间合并就好了

    #include<bits/stdc++.h>
    #define LL long long
    #define ls rt<<1
    #define rs (rt<<1|1)
    using namespace std;
    void read(int &x){
        char c = getchar();
        x = 0;
        while(c < '0' || c > '9') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar();
    }
    const int mod = 1e9 + 7;
    const int N = 1e5 + 10;
    
    struct MAT{
        int a[3][3];
        void change(){
            swap(a[0][2],a[1][2]);
            swap(a[0][0],a[1][1]);
            swap(a[0][1],a[1][0]);
        }
    }s[N << 2];
    void add(int &x,int y){
        x += y;
        if(x >= mod) x -= mod;
    }
    MAT mul(MAT A,MAT B){
      MAT ans;
      for(int i = 0;i < 3;i++){
        for(int j = 0;j < 3;j++){
            ans.a[i][j] = 0;
            for(int k = 0;k < 3;k++){
                add(ans.a[i][j],1LL * A.a[i][k] * B.a[k][j]%mod);
            }
        }
      }
      return ans;
    }
    MAT mat[3];
    int col[N << 2];
    char S[N];
    void init(){
        for(int k = 0;k < 3;k++)
            for(int i = 0;i < 3;i++)
                for(int j = 0;j < 3;j++)
                    mat[k].a[i][j] = i == j?1:0;
        mat[1].a[0][1] = mat[1].a[0][2] = 1;
        mat[2].a[1][0] = mat[2].a[1][2] = 1;
    }
    void pushdown(int rt){
        if(col[rt]){
            col[rs] ^= 1;
            col[ls] ^= 1;
            s[rs].change();
            s[ls].change();
            col[rt] = 0;
        }
    }
    void flip(int L,int R,int l,int r,int rt){
        if(L <= l && R >= r){
            col[rt] ^= 1;
            s[rt].change();
            return ;
        }
        pushdown(rt);
        int m = l + r >> 1;
        if(L <= m) flip(L,R,l,m,ls);
        if(R > m) flip(L,R,m+1,r,rs);
        s[rt] = mul(s[rs], s[ls]);
    }
    MAT query(int L,int R,int l,int r,int rt){
        if(L <= l && R >= r) return s[rt];
        pushdown(rt);
        int m = l + r >> 1;
        if(L <= m && R > m) return mul(query(L,R,m+1,r,rs),query(L,R,l,m,ls));
        if(L <= m) return query(L,R,l,m,ls);
        if(R > m) return query(L,R,m+1,r,rs);
    }
    void build(int l,int r,int rt){
        col[rt] = 0;
        if(l == r){
            s[rt] = mat[S[l] - '0' + 1];
            col[rt] = 0;
            return ;
        }
        int m = l + r>>1;
        build(l,m,ls);
        build(m+1,r,rs);
        s[rt] = mul(s[rs], s[ls]);
    }
    int main(){
        init();
        int T,o,l,r,n,q;
        read(T);
        while(T--){
            read(n),read(q);
            scanf("%s",S+1);
            build(1,n,1);
            while(q--){
                read(o),read(l),read(r);
                if(o == 1)  flip(l,r,1,n,1);
                else{
                    MAT ans = query(l,r,1,n,1);
                    int tmp = (ans.a[0][2]+ans.a[1][2])%mod;
                    printf("%d
    ",tmp);
                }
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    Java代码实现依赖注入
    Linux shell脚本的字符串截取
    Android教程:wifi热点问题
    Android framework层实现实现wifi无缝切换AP
    http mimetype为multipart/x-mixed-replace报文
    Realtek 8192cu 支持 Android Hotspot 软ap
    http协议详解
    Android 在一个程序中启动另一个程序(包名,或者类名)
    linux定时器
    进程与线程的一个简单解释(转)
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7400707.html
Copyright © 2020-2023  润新知