话说这题比赛时候过的好少,连题都没读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. ListView多选和单选模式重新整理

    超简单的单选和多选ListView 在开发过程中,我们经常会使用ListView去呈现列表数据,比如商品列表,通话记录,联系人列表等等,在一些情况下,我们还需要去选择其中的一些列表数据进行编辑.以前, ...

  2. HDU - 2102 A计划 【BFS】

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2102 思路 题目有两个坑点 0.Output 说 能在T时刻 找到公主 就输出 YES 但实际上 只要 ...

  3. Builder 模式初探

    Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细的控制对象的构造流程.该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的 ...

  4. Java多线程系列 基础篇05 synchronized关键字

    1. synchronized原理 在java中,每一个对象有且仅有一个同步锁,所以同步锁是依赖于对象而存在.当我们调用某对象的synchronized方法时,就获取了该对象的同步锁.例如,synch ...

  5. Python多人聊天室

    一.目的 以实现小项目的方式,来巩固之前学过的Python基本语法以及相关的知识. 二.相关技术: 1.wxpython GUI编程 2.网络编程 3.多线程编程 4.数据库编程 5.简单的将数据导出 ...

  6. Storm worker 并行度等理解

    Storm 调优是非常重要的, 仅次于写出正确的代码, 好在Storm官网上有关于worker executors tasks的介绍, http://storm.incubator.apache.or ...

  7. java高级特性增强

    第4天 java高级特性增强 今天内容安排: 1.掌握多线程 2.掌握并发包下的队列 3.了解JMS 4.掌握JVM技术 5.掌握反射和动态代理 java多线程增强 .1. java多线程基本知识 . ...

  8. 如何设置android studio让程序运行在真机中

    1.Run——>Edit Configurations... 2.运行

  9. Eclipse_插件_03_反编译插件_Eclipse Class Decompiler

    一.插件优势 此插件比jd-eclipse更加强大,反编译之后不会像jd-eclipse一样出现注释符号. 二.插件下载地址 1.github https://github.com/cnfree/Ec ...

  10. L90

    On Motes and Beams 微尘与栋梁 It is curious that our own offenses should seem so much less heinous than t ...