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] + 1 , f[i][0] = f[i-1][0]\)
\(\ \ if(!A[i]) f[i][0] = f[i-1][0] + f[i-1][1] + 1 , f[i][1] = f[i-1][1]\)
很整齐,我们来写成矩阵的样子: \(f[i,0]\ f[i,1]\ 1=f[i-1,0]\ f[i-1,1]\ 1\ *\ M\)
算了不写了。。这儿写比较麻烦 不妨看这
最后可得 原序列为0/1的位置 分别为两个仅互换1,2行 1,2列的矩阵M[0/1]
[l,r]的dp值就是区间矩阵乘积的结果 \(ans = f[i,0]+f[i,1]( f[i,0]\ f[i,1]\ 1 = 0\ 0\ 1 * M[l,r])\)
/*
注: Modify时标记不要改两次--
*/
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define gc() getchar()
const int N=1e5+5,mod=1e9+7;
const int M[2][3][3]={{1,0,0,1,1,0,1,0,1},{1,1,0,0,1,0,0,1,1}};//0 1
int n,m,A[N];
char s[N];
struct Matrix
{
int mat[3][3];
// Matrix() {memset(mat,0,sizeof mat);}
Matrix operator *(const Matrix &a)const
{
Matrix res;
for(int i=0; i<3; ++i)
for(int j=0; j<3; ++j)
{
res.mat[i][j]=0;
for(int k=0; k<3; ++k)
res.mat[i][j] += 1LL*mat[i][k]*a.mat[k][j]%mod,
res.mat[i][j] >= mod ? res.mat[i][j]-=mod : 0;//还是喜欢紧凑些--
}
return res;
}
};
struct Seg_Tree
{
Matrix mat[N<<2];
bool tag[N<<2];
inline void PushUp(int rt)
{
mat[rt]=mat[rt<<1]*mat[rt<<1|1];
}
inline void Init(int rt,int opt)
{
for(int i=0; i<3; ++i)
for(int j=0; j<3; ++j)
mat[rt].mat[i][j]=M[opt][i][j];
// if(opt)
// mat[rt].mat[0][0]=mat[rt].mat[0][1]=mat[rt].mat[1][1]=mat[rt].mat[2][1]=mat[rt].mat[2][2]=1;
// else
// mat[rt].mat[0][0]=mat[rt].mat[1][0]=mat[rt].mat[1][1]=mat[rt].mat[2][0]=mat[rt].mat[2][2]=1;
}
void Swap(int rt)
{
// for(int i=0; i<3; ++i)//swap(Line 1,Line 2)
// std::swap(mat[rt].mat[0][i], mat[rt].mat[1][i]);
// for(int i=0; i<3; ++i)//swap(Column 1,Column 2)
// std::swap(mat[rt].mat[i][0], mat[rt].mat[i][1]);
std::swap(mat[rt].mat[0][0],mat[rt].mat[1][0]),
std::swap(mat[rt].mat[0][1],mat[rt].mat[1][1]),
std::swap(mat[rt].mat[0][2],mat[rt].mat[1][2]),
std::swap(mat[rt].mat[0][0],mat[rt].mat[0][1]),
std::swap(mat[rt].mat[1][0],mat[rt].mat[1][1]),
std::swap(mat[rt].mat[2][0],mat[rt].mat[2][1]),
tag[rt]^=1;
}
void PushDown(int rt)
{
Swap(rt<<1), Swap(rt<<1|1);
tag[rt]=0;
}
void Build(int l,int r,int rt)
{
tag[rt]=0;
if(l==r)
if(A[l]) Init(rt,1);
else Init(rt,0);
else
{
int m=l+r>>1;
Build(l,m,rt<<1), Build(m+1,r,rt<<1|1);
PushUp(rt);
}
}
void Modify_Flip(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R) Swap(rt);//, tag[rt]^=1;//WA
else
{
if(tag[rt]) PushDown(rt);
int m=l+r>>1;
if(L<=m) Modify_Flip(l,m,rt<<1,L,R);
if(m<R) Modify_Flip(m+1,r,rt<<1|1,L,R);
PushUp(rt);
}
}
Matrix Query(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R) return mat[rt];
if(tag[rt]) PushDown(rt);
int m=l+r>>1;
if(L<=m)
if(m<R) return Query(l,m,rt<<1,L,R)*Query(m+1,r,rt<<1|1,L,R);
else return Query(l,m,rt<<1,L,R);
else return Query(m+1,r,rt<<1|1,L,R);
}
}t;
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("1.in","r",stdin);
#endif
int T=read();
while(T--)
{
n=read(),m=read();
scanf("%s",s+1);
for(int i=1; i<=n; ++i) A[i]=s[i]-'0';
t.Build(1,n,1);
int opt,l,r; Matrix res;
while(m--)
{
opt=read(),l=read(),r=read();
if(opt==1) t.Modify_Flip(1,n,1,l,r);
else
res = t.Query(1,n,1,l,r),
printf("%d\n",(res.mat[2][0]+res.mat[2][1])%mod);
}
}
return 0;
}
HDU.6155.Subsequence Count(线段树 矩阵)的更多相关文章
- HDU 6155 Subsequence Count 线段树维护矩阵
Subsequence Count Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Oth ...
- [HDU6155]Subsequence Count(线段树+矩阵)
DP式很容易得到,发现是线性递推形式,于是可以矩阵加速.又由于是区间形式,所以用线段树维护. https://www.cnblogs.com/Miracevin/p/9124511.html 关键在于 ...
- HDU 6155 Subsequence Count(矩阵乘法+线段树+基础DP)
题意 给定一个长度为 \(n\) 的 \(01\) 串,完成 \(m\) 种操作--操作分两种翻转 \([l,r]\) 区间中的元素.求区间 \([l,r]\) 有多少个不同的子序列. \(1 \le ...
- 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] ...
- HDU 6155 Subsequence Count (DP、线性代数、线段树)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6155 题解 DP+线代好题.(考场上过多时间刚前两题,没怎么想这题--) 首先列出一个DP式: 设\( ...
- 2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6155 Subsequence Count 矩阵快速幂
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6155 题意: 题解来自:http://www.cnblogs.com/iRedBean/p/73982 ...
- hdu 6155 - Subsequence Count
话说这题比赛时候过的好少,连题都没读TOT 先考虑dp求01串的不同子序列的个数. dp[i][j]表示用前i个字符组成的以j为结尾的01串个数. 如果第i个字符为0,则dp[i][0] = dp[i ...
- hdu 5700区间交(线段树)
区间交 Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submiss ...
- Wannafly Winter Camp 2019.Day 8 div1 E.Souls-like Game(线段树 矩阵快速幂)
题目链接 \(998244353\)写成\(99824435\)然后调这个线段树模板1.5h= = 以后要注意常量啊啊啊 \(Description\) 每个位置有一个\(3\times3\)的矩阵, ...
随机推荐
- NandFlash和iNand
nand 1.nand的单元组织:block与page(大页Nand与小页Nand)(1)Nand的页和以前讲过的块设备(尤其是硬盘)的扇区是类似的.扇区最早在磁盘中是512字节,后来也有些高级硬盘扇 ...
- Sql 正确删除用户过期的数据
怎样才算是正确的删除过期的数据呢?先交代一下前提,XX网站上面有一个放心企业专区,办理超级会员即可成为放心企业,放心企业可设置推荐职位展示在放心企业专区,信息都是存放在Info表中的,所谓的推荐职位就 ...
- apache服务器的常用功能及设置
安装httpd yum -y install httpd 服务脚本:/etc/rc.d/init.d/httpd 脚本配置文件:/etc/sysconfig/httpd ...
- webstrom随手笔记
1.node代码智能提示功能: 2.页面代码格式化快捷键: Ctrl+Alt+L键,或者Code =>Rearrange code
- IntelliJ IDEA 下的svn配置及使用的非常详细的图文总结
首先,使用的时候,自己得先在电脑上安装个小乌龟.也就是svn啦. 第一步安装小乌龟. 如下: 具体安装好像没什么具体要求,一路next,就好. 如上图箭头所示,在安装 TortoiseSVN 的时候, ...
- Java集合(Collection)综述
1.集合简介 数学定义:一般地,我们把研究对象统称为元素.把一些元素组成的总体叫做集合. java集合定义:集合就是一个放数据的容器,准确的说是放数据对象引用的容器. java中通用集合类存放于jav ...
- hdu2476
/* dp[l][r]表示将任意串的[l,r]刷成s2样子的最小代价 ans[i]表示将s1的前i位刷成s2的代价 按照区间dp的常用做法,dp[l][r]的状态由dp[l][k],dp[k+1][r ...
- 《剑指offer》-旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数 ...
- ERP退货系统管理(四十五)
添加的存储过程:(添加退货申请信息的存储过程) CREATE PROCEDURE [dbo].[BioBackSendGoods_ADD] @SendBackID INT OUTPUT, ), @Ap ...
- OpenLDAP在win2008上安装配置
业务需要,将企业员工信息统一管理,OpenLdap是目录数据库和一套访问协议组成的系统,适合使用,它有以下特点: LDAP的结构用树来表示 C/S模型,Server用户存储数据,Client为操作目录 ...