[HDU6155]Subsequence Count
题目大意:
给定一个01序列,支持以下两种操作:
1.区间反转;
2.区间求不同的子序列数量。
思路:
首先我们考虑区间反转,这是一个经典的线段树操作。
接下来考虑求不同的子序列数量,在已知当前区间的情况下,我们有如下$O(n)$的动态规划:|
$f_{i,0}=f_{i-1,0}+f_{i-1,1}+1,f_{i,1}=f_{i-1,1}//第i位为0$
$f_{i,1}=f_{i-1,0}+f_{i-1,1}+1,f_{i,0}=f_{i-1,0}//第i位为1$
这样的动态规划显然无法直接用线段树维护,而如果不能直接用线段树维护,上面维护的区间反转也就失去了意义。
为了使用线段树维护这种动态规划,我们需要用矩阵表示这种递推关系。
$\left(\begin{array}{}f_{i+1,0}\\f_{i+1,1}\\1\end{array}\right)=\left(\begin{array}{}f_{i-1,0}\\f_{i-1,1}\\1\end{array}\right)\times\left(\begin{array}{}1&0&0\\1&1&0\\1&0&1\end{array}\right)$
$\left(\begin{array}{}f_{i+1,0}\\f_{i+1,1}\\1\end{array}\right)=\left(\begin{array}{}f_{i-1,0}\\f_{i-1,1}\\1\end{array}\right)\times\left(\begin{array}{}1&1&0\\0&1&0\\0&1&1\end{array}\right)$
这样我们就可以保存每个区间的乘积,询问时直接相乘即可。
#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
inline int getdigit() {
char ch;
while(!isdigit(ch=getchar()));
return ch^'';
}
const int N=,mod=1e9+;
template<int SIZE>
struct Matrix {
int val[SIZE][SIZE];
Matrix operator * (const Matrix &another) const {
Matrix ret;
for(int i=;i<SIZE;i++) {
for(int j=;j<SIZE;j++) {
ret.val[i][j]=;
for(int k=;k<SIZE;k++) {
ret.val[i][j]+=(long long)val[i][k]*another.val[k][j]%mod;
ret.val[i][j]%=mod;
}
}
}
return ret;
}
void operator *= (const Matrix &another) {
*this=*this*another;
}
void flip() {
std::swap(val[][],val[][]);
std::swap(val[][],val[][]);
std::swap(val[][],val[][]);
std::swap(val[][],val[][]);
}
int calc() {
return (val[][]+val[][])%mod;
}
};
const Matrix<> m[]={
{,,,
,,,
,,},
{,,,
,,,
,,}
};
const Matrix<> E={
,,,
,,,
,,
};
class SegmentTree {
private:
#define _left <<1
#define _right <<1|1
Matrix<> val[N<<];
bool tag[N<<];
void push_up(const int p) {
val[p]=val[p _left]*val[p _right];
}
void push_down(const int p) {
if(!tag[p]) return;
val[p _left].flip();
val[p _right].flip();
tag[p _left]^=true;
tag[p _right]^=true;
tag[p]=false;
}
public:
void build(const int p,const int b,const int e) {
tag[p]=false;
if(b==e) {
val[p]=m[getdigit()];
return;
}
int mid=(b+e)>>;
build(p _left,b,mid);
build(p _right,mid+,e);
push_up(p);
}
void modify(const int p,const int b,const int e,const int l,const int r) {
if(b==l&&e==r) {
val[p].flip();
tag[p]^=true;
return;
}
push_down(p);
int mid=(b+e)>>;
if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r));
if(r>mid) modify(p _right,mid+,e,std::max(mid+,l),r);
push_up(p);
}
Matrix<> query(const int p,const int b,const int e,const int l,const int r) {
if(b==l&&e==r) {
return val[p];
}
push_down(p);
int mid=(b+e)>>;
Matrix<> ret=E;
if(l<=mid) ret*=query(p _left,b,mid,l,std::min(mid,r));
if(r>mid) ret*=query(p _right,mid+,e,std::max(mid+,l),r);
return ret;
}
};
SegmentTree t;
int main() {
for(int T=getint();T;T--) {
int n=getint(),q=getint();
t.build(,,n);
while(q--) {
int op=getint(),l=getint(),r=getint();
switch(op) {
case : {
t.modify(,,n,l,r);
break;
}
case : {
printf("%d\n",t.query(,,n,l,r).calc());
break;
}
}
}
}
return ;
}
[HDU6155]Subsequence Count的更多相关文章
- [HDU6155]Subsequence Count(线段树+矩阵)
DP式很容易得到,发现是线性递推形式,于是可以矩阵加速.又由于是区间形式,所以用线段树维护. https://www.cnblogs.com/Miracevin/p/9124511.html 关键在于 ...
- HDU 6155 Subsequence Count 线段树维护矩阵
Subsequence Count Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Oth ...
- 2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6155 Subsequence Count 矩阵快速幂
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6155 题意: 题解来自:http://www.cnblogs.com/iRedBean/p/73982 ...
- Subsequence Count (线段树)
Time Limit: 1000 ms Memory Limit: 256 MB Description 给定一个01串 $S_{1 \cdots n}$ 和 $Q$ 个操作. 操作有两种类型: ...
- 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] + ...
- HDU 6155 Subsequence Count(矩阵乘法+线段树+基础DP)
题意 给定一个长度为 \(n\) 的 \(01\) 串,完成 \(m\) 种操作--操作分两种翻转 \([l,r]\) 区间中的元素.求区间 \([l,r]\) 有多少个不同的子序列. \(1 \le ...
- Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵
Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries ...
- [Contest20171006]Subsequence Count
给定一个01串$S_{1\cdots n}$和$Q$个操作.操作有两种类型:1.将$[l,r]$区间的数取反(将其中的$0$变成$1$,$1$变成$0$).2.询问字符串$S$的子串$S_{l\cdo ...
- hdu 6155 - Subsequence Count
话说这题比赛时候过的好少,连题都没读TOT 先考虑dp求01串的不同子序列的个数. dp[i][j]表示用前i个字符组成的以j为结尾的01串个数. 如果第i个字符为0,则dp[i][0] = dp[i ...
随机推荐
- C++ 之Boost 实用工具类及简单使用
本文将介绍几个 Boost 实用工具类,包括 tuple.static_assert.pool.random 和 program_options等等.需要对标准 STL 具备一定的了解才能充分理解本文 ...
- idea中JDK失效
[问题] 在没有改变任何东西的情况下,突然间IDEA里面所有的代码都标红,无法找到JDK [解决方法] [File]->[Invalidate Caches],然后就好了
- Python 模块进阶
import导入模块 1. import 搜索路径 import sys sys.path 例子: In [1]: import sys In [2]: sys.path Out[2]: ['', ' ...
- 在虚拟机(vmware)上安装CentOS
第一步是安装虚拟机,这个比较简单就不讲了. 第二步准备CentOS的镜像文件准备安装 第三步安装CentOS: 新建虚拟机 选择自定义配置 选择硬件兼容标准 选择是否让vmware安装操作系统 选择将 ...
- AdvStringGrid 复选框、goRowSelect
var I: Integer; begin do begin AdvStringGrid1.AddCheckBox(, I, True, True); AdvStringGrid1.Cells[,I] ...
- C/C++之static
C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static.前者应用于普通变量和函数,不涉及类:后者主要说明static在类中的作用. 1.面向过程设计中的st ...
- » Working Around JNI UTF-8 Strings Deprogramming
private static native void printString(String text); ... void examplePrintString() { String str = &q ...
- WeifenLuo.WinFormsUI.Docking"的使用
要用 WeifenLuo.WinFormsUI.Docking 首先要下载: WeifenLuo.WinFormsUI.Docking 在当前工程“解决方案 - 引用”中 >> 右击引用 ...
- Java之反转排序
顾名思义,反转排序就是以相反的顺序把原来的数组内容重新进行排序.反转排序算法在我们的程序开发中也是经常用到的.而反转排序的基本思想也很简单,就是把数组最后一个元素与第一个元素进行交换,倒数第二个与第二 ...
- 一步一步学习IdentityServer3 (11) OAuth2
OAuth中定义了四个Role 资源所有者:这里可以理解为一个用户 资源服务器:如同前面章节中的 Web站点或者WebApi 服务资源站点 客户端:这里是Client,如同Identityserver ...