[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 ...
随机推荐
- 推荐一本springBoot学习书籍---深入浅出springBoot2.x
花了几周时间读完了这本书,确实是一本特别详细全面的书,而且不单单只是springBoot, 书中还介绍了许多工作中常用的技术与springBoot的整合使用,当然,也有一些小bug, 因为在代码实践过 ...
- 高级C#信使(译) - Unity维基百科
高级C#信使 作者:Ilya Suzdalnitski 译自:http://wiki.unity3d.com/index.php/Advanced_CSharp_Messenger 描述 前言 Mis ...
- Linux时间子系统之七:定时器的应用--msleep(),hrtimer_nanosleep()【转】
转自:http://blog.csdn.net/droidphone/article/details/8104433 我们已经在前面几章介绍了低分辨率定时器和高精度定时器的实现原理,内核为了方便其它子 ...
- java递归遍历获取目录下所有文件
import java.io.File; import java.util.ArrayList; import java.util.List; public class GetFiles { Arra ...
- Python基础:内置常量
本文根据Python 3.6.5的官文Built-in Constants编写,官文比较短,大家可以直接看原文. 有一些存在于 内置名称空间(the built-in namespace) 的常量,如 ...
- MFC中CString.Format类详解
在MFC程序中,使用CString来处理字符串是一个很不错的选择.CString既可以处理Unicode标准的字符串,也可以处理ANSI标准的字符串.CString的Format方法给我们进行字符串的 ...
- GreenPlum学习笔记:create or replace function创建函数
原始表数据如下: 需求:现要求按分号“;”将rate_item列进行分割后插入到新的数据表中. CREATE OR REPLACE FUNCTION fun_gp_test_xxx_20181026( ...
- Effective STL 学习笔记 39 ~ 41
Effective STL 学习笔记 39 ~ 41 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- 聚类:(K-means)算法
1.归类: 聚类(clustering) 属于非监督学习 (unsupervised learning) 无类别标记(class label) 2.举例: 3. K-means 算法: ...
- CVE-2012-4969
Microsoft Internet Explorer ‘CMshtmlEd::Exec’函数释放后使用漏洞(CNNVD-201209-394) Microsoft Internet Explorer ...