题目大意:
  给定一个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的更多相关文章

  1. [HDU6155]Subsequence Count(线段树+矩阵)

    DP式很容易得到,发现是线性递推形式,于是可以矩阵加速.又由于是区间形式,所以用线段树维护. https://www.cnblogs.com/Miracevin/p/9124511.html 关键在于 ...

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

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

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

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

  4. Subsequence Count (线段树)

    Time Limit: 1000 ms   Memory Limit: 256 MB Description 给定一个01串 $S_{1 \cdots n}$ 和 $Q$ 个操作. 操作有两种类型: ...

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

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

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

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

  8. [Contest20171006]Subsequence Count

    给定一个01串$S_{1\cdots n}$和$Q$个操作.操作有两种类型:1.将$[l,r]$区间的数取反(将其中的$0$变成$1$,$1$变成$0$).2.询问字符串$S$的子串$S_{l\cdo ...

  9. hdu 6155 - Subsequence Count

    话说这题比赛时候过的好少,连题都没读TOT 先考虑dp求01串的不同子序列的个数. dp[i][j]表示用前i个字符组成的以j为结尾的01串个数. 如果第i个字符为0,则dp[i][0] = dp[i ...

随机推荐

  1. 富文本存储型XSS的模糊测试之道

    富文本存储型XSS的模糊测试之道 凭借黑吧安全网漏洞报告平台的公开案例数据,我们足以管中窥豹,跨站脚本漏洞(Cross-site Script)仍是不少企业在业务安全风险排查和修复过程中需要对抗的“大 ...

  2. 20165320 预备作业3 :Linux安装及命令入门

    一.VirtualBox与Linux的安装 我是按照老师给的链接下的最新版本的VirtualBox5.26,然后Ubuntu软件(版本是16.04,最新的是17)是自己在网上找的旧版本下好的,因为我在 ...

  3. python 面试题4

    Python面试题 基础篇 分类: Python2014-08-08 13:15 2071人阅读 评论(0) 收藏 举报 最近,整理了一些python常见的面试题目,语言是一种工具,但是多角度的了解工 ...

  4. 2016.6.26——Maximum Depth of Binary Tree

    Maximum Depth of Binary Tree 本题收获 1.树时使用递归 2.注意边界条件时输出的值,仔细阅读题意,若是面试时,问清边界条件. 题目: Given a binary tre ...

  5. iframe测试

    iframe类似于frameset,iframe 和 frameset 都用于html页面的框架布局.(都可用于后台管理界面,iframe放于body标签内,frameset不能放在body标签) 1 ...

  6. Oracle环境变量与中文显示的问题

    在CentOS(linux)下安装Oracle,对环境变量的设置有一些讲究. 一般我们可以把环境变量设置在/etc/profile文件中: # Oracle SettingsTMP=/tmp; exp ...

  7. 洛谷 P3307: bzoj 3202: [SDOI2013] 项链

    题目传送门:洛谷P3307.这题在bzoj上是权限题. 题意简述: 这题分为两个部分: ① 有一些珠子,每个珠子可以看成一个无序三元组.三元组要满足三个数都在$1$到$m$之间,并且三个数互质,两个珠 ...

  8. 系统架构之负载均衡【F5\nginx\LVS\DNS轮询\】

    在做系统架构规划的时候,负载均衡,HA(高可用性集群,是保证业务连续性的有效解决方案,一般有两个或两个以上的节点,且分为活动节点及备用节点,当活动节点出现故障的时候,由备用节点接管)都是经常需要考虑的 ...

  9. MySQL 修改数据

    UPDATE 语句 修改或更新 MySQL 中的数据,我们可以使用 SQL UPDATE 命令来操作. 可以同时修改 一个 或 多个 字段: 可以在where子句中指定条件: 可以在一个单独表中更新数 ...

  10. vue总结05 过渡--状态过渡

    状态过渡 Vue 的过渡系统提供了非常多简单的方法设置进入.离开和列表的动效.那么对于数据元素本身的动效呢,比如: 数字和运算 颜色的显示 SVG 节点的位置 元素的大小和其他的属性 所有的原始数字都 ...