话说这题比赛时候过的好少,连题都没读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. PHP使用Apache中的ab测试网站的压力性能

    打开Apache服务器的安装路径(我用的是 WampServer),在bin目录中有一个ab.exe的可执行程序,它就是要介绍的压力测试工具. 在Windows系统的命令行下,进入ab.exe程序所在 ...

  2. Data Structure Binary Tree: Level order traversal in spiral form

    http://www.geeksforgeeks.org/level-order-traversal-in-spiral-form/ #include <iostream> #includ ...

  3. 20145239 Linux下常用的ls命令总结

    20145239 Linux下常用的ls命令总结 通过学习本周的教学视频和要求掌握的内容,发现ls命令被使用的次数非常多,但作为一个初学者,可能我只会ls或者顶多ls -l两种用法.但其实ls是一个非 ...

  4. Spring Boot2.0之热部署原理

    所谓的热部署:比如项目的热部署,就是在应用程序在不停止的情况下,实现新的部署 原理: 实用类加载器(classloader重新读取字节码文件到jvm内存) 如何纯手写一个热部署功能: 1.监听 cla ...

  5. centos 7 部署 mysql 报错记录

    1. Header V3 DSA/SHA1 Signature, key ID 5072e1f5: NOKEY 这是由于yum安装了旧版本的GPG keys造成的,解决办法就是 引用  rpm --i ...

  6. python to 可执行文件

    cx_Freeze for Windows, Linux, and Mac OS X (Python 2.7, 3.x) pyinstaller for Windows, Linux, and Mac ...

  7. 分享知识-快乐自己:Oracle基本语法(创建:表空间、用户、授权、约束等)使用指南

    Oracle12c 与 Oracle11g 创建用户时有差别.Oracle12C默认为 CDB模式 这时创建用户的时候需要加上 c## 开头:例如:c##MLQ. --说明--需求:创建表空间(MLQ ...

  8. linux标准输入输出与重定向

    原文:http://blog.sina.com.cn/s/blog_8333cf8f0100vzzl.html##1 1. 标准输入输出和错误    linux下使用标准输入文件stdin和标准输出文 ...

  9. javaScript运算符之in运算符

  10. suse enterprise Linux 11上配置 oracle11g和tomcat开机自启动

    一.oracle 11g r2自启动 1.修改/etc/sysconfig/oracle文件: ORACLE_BASE=/oracle  //此处改为你安装的oracle目录 START_ORACLE ...