[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 ...
随机推荐
- cin.get()和cin.getline()之间的区别
cin.getline()和cin.get()都是对输入的面向行的读取,即一次读取整行而不是单个数字或字符,但是二者有一定的区别. cin.get()每次读取一整行并把由Enter键生成的换行符留在输 ...
- Vue 项目添加 promise polyfill
1. 安装依赖 npm install es6-promise --save 2. 在 main.js 上面引入: import 'es6-promise/auto'
- 20165320 预备作业3 :Linux安装及命令入门
一.VirtualBox与Linux的安装 我是按照老师给的链接下的最新版本的VirtualBox5.26,然后Ubuntu软件(版本是16.04,最新的是17)是自己在网上找的旧版本下好的,因为我在 ...
- TCP三次握手与四次挥手过程
TCP连接的建立(三次握手) 首先,客户端与服务器均处于未连接状态,并且是客户端主动向服务器请求建立连接: 客户端将报文段中的SYN=1(同步位),并选择一个seq=x,(即该请求报文的序号为x) ...
- Python基础之多线程事件Event
import threading,time class Boss(threading.Thread): def run(self): print("BOSS:伙计们今晚上加班到22:00&q ...
- Group Normalization笔记
作者:Yuxin,Wu Kaiming He 机构:Facebook AI Research (FAIR) 摘要:BN是深度学习发展中的一个里程碑技术,它使得各种网络得以训练.然而,在batch维度上 ...
- shell服务管理->
nginx.php等服务管理练习脚本 ->nginx的启动状态 root@jumpserver- day02]# cat nginx_web.sh #!/bin/bash source /etc ...
- 最后一面《HR面》------十大经典提问
1.HR:你希望通过这份工作获得什么? 1).自杀式回答:我希望自己为之工作的企业能够重视质量,而且会给做得好的员工予以奖励.我希望通过这份工作锻炼自己,提升自己的能力,能让公司更加重视我. a.“我 ...
- IntelliJ IDEA + Tomcat ;On Upate Action 与 On Frame Deactivation
On Upate Action 与 On Frame Deactivation 这两个选项的设置,依赖于 项目的部署方式 是war包 还是 exploded ,看下面的gif: 这里实在是太灵活了, ...
- FZU 1901 Period II(KMP循环节+公共前后缀)
题目链接:http://acm.fzu.edu.cn/problem.php?pid=1901 题目大意:题目大意求出所有p满足s[i]=s[i+p](i<=len-p) 解题思路: 其实就是要 ...