话说这题比赛时候过的好少,连题都没读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 + ;
const int mSize = ; struct Matrix
{
long long v[mSize][mSize];
friend Matrix operator* (const Matrix& a, const Matrix& b)
{
Matrix c;
for (int i = ; i < mSize; i++)
for (int j = ; j < mSize; j++)
{
c.v[i][j] = ;
for (int k = ; 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[] = {{, , , , , , , , }, {, , , , , , , , }}; Matrix data[ << ];
bool flip[ << ];
char s[]; void seq_build(int o, int l, int r)
{
if (l == r)
data[o] = m[s[l] - ''];
else
{
int mid = (l + r) >> ;
seq_build(o << , l, mid);
seq_build(o << | , mid + , r);
data[o] = data[o << ] * data[o << | ];
}
flip[o] = false;
} void doFlip(Matrix& mat)
{
swap(mat.v[][], mat.v[][]);
swap(mat.v[][], mat.v[][]);
swap(mat.v[][], mat.v[][]);
swap(mat.v[][], mat.v[][]);
swap(mat.v[][], mat.v[][]);
} void pushdown(int o)
{
if (flip[o])
{
flip[o << ] ^= flip[o];
flip[o << | ] ^= flip[o];
doFlip(data[o << ]);
doFlip(data[o << | ]);
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 {, , , , , , , , };
int mid = (l + r) >> ;
pushdown(o);
return seq_query(o << , l, mid, ql, qr) * seq_query(o << | , mid + , r, ql, qr);
} void seq_flip(int o, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr)
{
flip[o] ^= ;
doFlip(data[o]);
return;
}
if (r < ql || qr < l)
return;
int mid = (l + r) >> ;
pushdown(o);
seq_flip(o << , l, mid, ql, qr);
seq_flip(o << | , mid + , r, ql, qr);
data[o] = data[o << ] * data[o << | ];
} int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n, q;
scanf("%d%d", &n, &q);
scanf("%s", s + );
seq_build(, , n);
while (q--)
{
int op, l, r;
scanf("%d%d%d", &op, &l, &r);
if (op == )
seq_flip(, , n, l, r);
else
{
Matrix mat = seq_query(, , n, l, r);
printf("%I64d\n", (mat.v[][] + mat.v[][]) % mod);
}
}
}
return ;
}

----------Update----------

抱歉很久没有看cnblogs了,这里给出一个不太严谨的关于flip部分的证明

hdu 6155 - Subsequence Count的更多相关文章

  1. HDU 6155 Subsequence Count 线段树维护矩阵

    Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Oth ...

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

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6155 题意: 题解来自:http://www.cnblogs.com/iRedBean/p/73982 ...

  3. HDU 6155 Subsequence Count (DP、线性代数、线段树)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6155 题解 DP+线代好题.(考场上过多时间刚前两题,没怎么想这题--) 首先列出一个DP式: 设\( ...

  4. 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] + ...

  5. HDU 6155 Subsequence Count(矩阵乘法+线段树+基础DP)

    题意 给定一个长度为 \(n\) 的 \(01\) 串,完成 \(m\) 种操作--操作分两种翻转 \([l,r]\) 区间中的元素.求区间 \([l,r]\) 有多少个不同的子序列. \(1 \le ...

  6. 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] ...

  7. ccpc 网络赛 hdu 6155

    # ccpc 网络赛 hdu 6155(矩阵乘法 + 线段树) 题意: 给出 01 串,要么询问某个区间内不同的 01 子序列数量,要么把区间翻转. 叉姐的题解: 先考虑怎么算 \(s_1, s_2, ...

  8. 【hdu 6155】Subsequence Count

    题意 给定一个 \(01\) 串 \(S_{1...n}\) 和 \(Q\) 个操作. 操作有 \(2\) 种类型: 1. 将 \([l,r]\) 区间所有数取反(\(0→1,\space 1→0\) ...

  9. hdu 3530 Subsequence

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=3530 Subsequence Description There is a sequence of i ...

随机推荐

  1. Java基础教程:多线程基础(3)——阻塞队列

    Java基础教程:多线程基础(3)——阻塞队列 快速开始 引入问题 生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 模 ...

  2. P3968 [TJOI2014]电源插排

    P3968 [TJOI2014]电源插排 线段树维护最长空区间及左端点位置,这个和$nlongn$的动态最大子序和差不多,就不多解释了 $n$较大哈希优化空间 My complete code: #i ...

  3. Android Weekly Notes Issue #275

    Android Weekly Issue #275 September 17, 2017 Android Weekly Issue #275 本期内容包括给Google Map实现一个Marker A ...

  4. Android环境下通过C框架层控制WIFI【转】

    本文转载自:https://blog.csdn.net/edw200/article/details/52192631 本人是从事Linux嵌入式开发的,安卓wifi控制在安卓JAVA层已经做得非常成 ...

  5. Linux之make的用法讲解

    在 Linux环境下使用 GNU 的 make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译.连接以至于最后的执行.不过这需要我们投入一些时间去完成一个或者多个 ...

  6. javscript 一些常用的工具方法

    一些工作中经常会用到的js代码,可以封装成一个工具库. 积少成多,从现在开始吧! -------------- 1 . 判断一段文字的长度.要求中文相当于2个字符,非中文的相当于1个字符 String ...

  7. 左侧浮动html网页模板

    左侧浮动html网页模板是一款左侧导航菜单随网页滚动的html网站模板. 地址:http://www.huiyi8.com/sc/10617.html

  8. TP框架入门基础

    ThinkPHP目录: ThinkPHP主目录文件夹: Conf文件夹: Library文件夹: Library=>Think文件夹:

  9. tensorflow 线性回归 iris

    线性拟合

  10. 浅析linux 下shell命令执行和守护进程

    执行shell脚本有以下几种方式 1.相对路径方式,需先cd到脚本路径下 [root@banking tmp]# cd /tmp [root@banking tmp]# ./ceshi.sh 脚本执行 ...