hdu 6155 - Subsequence Count

话说这题比赛时候过的好少,连题都没读TOT

先考虑dp求01串的不同子序列的个数。

dp[i][j]表示用前i个字符组成的以j为结尾的01串个数。

如果第i个字符为0,则dp[i][0] = dp[i-1][1] + dp[i-1][0] + 1,dp[i][1] = dp[i-1][1]

如果第i个字符为1,则dp[i][1] = dp[i-1][1] + dp[i-1][0] + 1,dp[i][0] = dp[i-1][0]

显然这是线性递推,我们考虑如何用矩阵表示这种递推关系。

下面分别对应加入一个字符0或1时表示递推关系的矩阵。

然后用线段树维护每个区间的矩阵乘积就可以解决查询操作了。

对于修改操作,我们给区间维护一个flip标记,表示该区间是否要翻转,用线段树区间更新的方法去更新flip标记就好了。

将一个区间翻转后,它对应矩阵也要发生改变,这里我们只要将矩阵的第一列与第二列交换后再将第一行与第二行交换就好了。

#include <bits/stdc++.h>
using namespace std;

const long long mod = 1e9 + 7;
const int mSize = 3;

struct Matrix
{
    long long v[mSize][mSize];
    friend Matrix operator* (const Matrix& a, const Matrix& b)
    {
        Matrix c;
        for (int i = 0; i < mSize; i++)
            for (int j = 0; j < mSize; j++)
            {
                c.v[i][j] = 0;
                for (int k = 0; k < mSize; k++)
                    c.v[i][j] += a.v[i][k] * b.v[k][j] % mod;
                c.v[i][j] %= mod;
            }
        return c;
    }
};

const Matrix m[2] = {{1, 0, 0, 1, 1, 0, 1, 0, 1}, {1, 1, 0, 0, 1, 0, 0, 1, 1}};

Matrix data[100005 << 2];
bool flip[100005 << 2];
char s[100005];

void seq_build(int o, int l, int r)
{
    if (l == r)
        data[o] = m[s[l] - ‘0‘];
    else
    {
        int mid = (l + r) >> 1;
        seq_build(o << 1, l, mid);
        seq_build(o << 1 | 1, mid + 1, r);
        data[o] = data[o << 1] * data[o << 1 | 1];
    }
    flip[o] = false;
}

void doFlip(Matrix& mat)
{
    swap(mat.v[0][0], mat.v[0][1]);
    swap(mat.v[1][0], mat.v[1][1]);
    swap(mat.v[2][0], mat.v[2][1]);
    swap(mat.v[0][0], mat.v[1][0]);
    swap(mat.v[0][1], mat.v[1][1]);
}

void pushdown(int o)
{
    if (flip[o])
    {
        flip[o << 1] ^= flip[o];
        flip[o << 1 | 1] ^= flip[o];
        doFlip(data[o << 1]);
        doFlip(data[o << 1 | 1]);
        flip[o] = false;
    }
}

Matrix seq_query(int o, int l, int r, int ql, int qr)
{
    if (ql <= l && r <= qr)
        return data[o];
    if (r < ql || qr < l)
        return {1, 0, 0, 0, 1, 0, 0, 0, 1};
    int mid = (l + r) >> 1;
    pushdown(o);
    return seq_query(o << 1, l, mid, ql, qr) * seq_query(o << 1 | 1, mid + 1, r, ql, qr);
}

void seq_flip(int o, int l, int r, int ql, int qr)
{
    if (ql <= l && r <= qr)
    {
        flip[o] ^= 1;
        doFlip(data[o]);
        return;
    }
    if (r < ql || qr < l)
        return;
    int mid = (l + r) >> 1;
    pushdown(o);
    seq_flip(o << 1, l, mid, ql, qr);
    seq_flip(o << 1 | 1, mid + 1, r, ql, qr);
    data[o] = data[o << 1] * data[o << 1 | 1];
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n, q;
        scanf("%d%d", &n, &q);
        scanf("%s", s + 1);
        seq_build(1, 1, n);
        while (q--)
        {
            int op, l, r;
            scanf("%d%d%d", &op, &l, &r);
            if (op == 1)
                seq_flip(1, 1, n, l, r);
            else
            {
                Matrix mat = seq_query(1, 1, n, l, r);
                printf("%I64d\n", (mat.v[2][0] + mat.v[2][1]) % mod);
            }
        }
    }
    return 0;
}
时间: 2024-08-06 07:54:46

hdu 6155 - Subsequence Count的相关文章

HDU 6155 Subsequence Count 线段树维护矩阵

Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string. There are two types of querie

2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6155 Subsequence Count 矩阵快速幂

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6155 题意: 题解来自:http://www.cnblogs.com/iRedBean/p/7398272.html 先考虑dp求01串的不同子序列的个数. dp[i][j]表示用前i个字符组成的以j为结尾的01串个数. 如果第i个字符为0,则dp[i][0] = dp[i-1][1] + dp[i-1][0] + 1,dp[i][1] = dp[i-1][1] 如果第i个字符为1,则dp[i][1

HDU.6155.Subsequence Count(线段树 矩阵)

题目链接 首先考虑询问[1,n]怎么做 设 f[i][0/1]表示[1,i]以0/1结尾的不同子序列个数 则\(if(A[i]) f[i][1] = f[i-1][0] + f[i-1][1] + 1 , f[i][0] = f[i-1][0]\) \(\ \ if(!A[i]) f[i][0] = f[i-1][0] + f[i-1][1] + 1 , f[i][1] = f[i-1][1]\) 很整齐,我们来写成矩阵的样子: \(f[i,0]\ f[i,1]\ 1=f[i-1,0]\ f[i

HDU 6155 Subsequence Count(矩阵 + DP + 线段树)题解

题意:01串,操作1:把l r区间的0变1,1变0:操作2:求出l r区间的子序列种数 思路:设DP[i][j]为到i为止以j结尾的种数,假设j为0,那么dp[i][0] = dp[i - 1][1] + dp[i -1][0] (0结尾新串) + dp[i - 1][0] (0结尾旧串) - dp[i - 1][0] (重复) + 1(0本身被重复时去除). 那么可以得到转移时的矩阵 $$ \left( \begin{matrix} dp[i - 1][0] & dp[i - 1][1] &am

hdu 3530 Subsequence

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=3530 Subsequence Description There is a sequence of integers. Your task is to find the longest subsequence that satisfies the following condition: the difference between the maximum element and the minim

hdu 5878 I Count Two Three (2016 ACM/ICPC Asia Regional Qingdao Online 1001)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5878 题目大意: 给出一个数n ,求一个数X, X>=n. X 满足一个条件 X= 2^a*3^b*5^c*7^d 求靠近n的X值. 解题思路: 打表+二分查找 [切记用 cin cout,都是泪...] AC Code: 1 #include<bits/stdc++.h> 2 using namespace std; 3 long long na[100002]; 4 5 int main

HDU 5056 Boring count(数学)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5056 Problem Description You are given a string S consisting of lowercase letters, and your task is counting the number of substring that the number of each lowercase letter in the substring is no more t

HDU 3530 Subsequence(单调队列)

Problem Description There is a sequence of integers. Your task is to find the longest subsequence that satisfies the following condition: the difference between the maximum element and the minimum element of the subsequence is no smaller than m and n

hdu 5056 Boring count

http://acm.hdu.edu.cn/showproblem.php?pid=5056 题意:给你一个字符串,然后找出子串中每一个字母出现次数小于等于k的个数. 思路:枚举字符串下标i,每次计算以i为结尾的符合条件的最长串.那么以i为结尾的符合条件子串个数就是最长串的长度.求和即可. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 100010 5 #de