HDU 6155 Subsequence Count(矩阵乘法+线段树+基础DP)
题意
给定一个长度为 \(n\) 的 \(01\) 串,完成 \(m\) 种操作——操作分两种翻转 \([l,r]\) 区间中的元素、求区间 \([l,r]\) 有多少个不同的子序列。
\(1 \leq n,m \leq 10^5\)
思路
看到这种题目,应该条件反射的去想一下线段树。
但首先还是从一个询问开始,对于一个长度为 \(n\) 的串,设 \(dp_{i,j}\) 为前 \(i\) 位组成的序列中,以 \(j\) 结尾的串的个数,若串的第 \(i\) 位为 \(j\) 有递推式:
\(dp_{i,j}=dp_{i-1,0}+dp_{i-1,1}+1\)
\(dp_{i,!j}=dp_{i-1,!j}\)
上式是以 \(0j,1j\) 结尾的串的个数,加上单独一个\(j\) ;下式则直接转移上一位的信息。
那么将 \(\{dp_{0,0},dp_{0,1},1\}\) 作为初始矩阵,用线段树维护区间对应的转移矩阵即可。
代码
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=1e5+5;
const int P=1e9+7;
struct Matrix
{
int n,m,a[4][4];
int *operator [](const int x){return a[x];}
void resize(int _n,int _m){n=_n,m=_m;}
Matrix operator *(const Matrix &_)const
{
Matrix res;res.resize(n,_.m);
FOR(i,1,n)FOR(j,1,_.m)
{
res[i][j]=0;
FOR(k,1,m)(res[i][j]+=1ll*a[i][k]*_.a[k][j]%P)%=P;
}
return res;
}
void flip()
{
swap(a[1][1],a[2][2]);
swap(a[1][2],a[2][1]);
swap(a[3][1],a[3][2]);
}
Matrix operator *=(const Matrix &_){return (*this)=(*this)*_;}
};
const Matrix Zero=(Matrix){
3,3,
0,0,0,0,
0,1,0,0,
0,1,1,0,
0,1,0,1};
const Matrix One =(Matrix){
3,3,
0,0,0,0,
0,1,1,0,
0,0,1,0,
0,0,1,1};
Matrix nd[N<<2],A;
int tag[N<<2];
char str[N];
void build(int k,int l,int r)
{
tag[k]=0;
if(l==r)
{
if(str[l]=='0')nd[k]=Zero;
else nd[k]=One;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
nd[k]=nd[k<<1]*nd[k<<1|1];
}
void push_down(int k)
{
if(!tag[k])return;
tag[k<<1]^=1,nd[k<<1].flip();
tag[k<<1|1]^=1,nd[k<<1|1].flip();
tag[k]=0;
}
void update(int k,int L,int R,int l,int r)
{
if(L<=l&&r<=R)
{
tag[k]^=1,nd[k].flip();
return;
}
push_down(k);
int mid=(l+r)>>1;
if(L<=mid)update(k<<1,L,R,l,mid);
if(R>mid)update(k<<1|1,L,R,mid+1,r);
nd[k]=nd[k<<1]*nd[k<<1|1];
}
Matrix query(int k,int L,int R,int l,int r)
{
if(L<=l&&r<=R)return nd[k];
push_down(k);
int mid=(l+r)>>1;
if(R<=mid)return query(k<<1,L,R,l,mid);
else if(L>mid)return query(k<<1|1,L,R,mid+1,r);
else return query(k<<1,L,R,l,mid)*query(k<<1|1,L,R,mid+1,r);
}
int main()
{
A.resize(1,3);
A[1][1]=0,A[1][2]=0,A[1][3]=1;
int T,n,Q;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&Q);
scanf("%s",str+1);
build(1,1,n);
int op,x,y;
while(Q--)
{
scanf("%d%d%d",&op,&x,&y);
if(op==1)update(1,x,y,1,n);
else
{
Matrix res=A*query(1,x,y,1,n);
printf("%d\n",(res[1][1]+res[1][2])%P);
}
}
}
return 0;
}
HDU 6155 Subsequence Count(矩阵乘法+线段树+基础DP)的更多相关文章
- 2017中国大学生程序设计竞赛 - 网络选拔赛 HDU 6155 Subsequence Count 矩阵快速幂
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6155 题意: 题解来自:http://www.cnblogs.com/iRedBean/p/73982 ...
- HDU 3074.Multiply game-区间乘法-线段树(单点更新、区间查询),上推标记取模
Multiply game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...
- HDU 6155 Subsequence Count 线段树维护矩阵
Subsequence Count Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Oth ...
- 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式: 设\( ...
- THUSCH 2017 大魔法师(矩阵乘法+线段树)
题意 https://loj.ac/problem/2980 思路 区间修改考虑用线段树维护.由于一段区间的 \(A,B,C\) 可以表示成由原来的 \(A,B,C\) 乘上带上系数再加上某一个某个常 ...
- Luogu P4643 【模板】动态dp(矩阵乘法,线段树,树链剖分)
题面 给定一棵 \(n\) 个点的树,点带点权. 有 \(m\) 次操作,每次操作给定 \(x,y\) ,表示修改点 \(x\) 的权值为 \(y\) . 你需要在每次操作之后求出这棵树的最大权独立集 ...
- ZOJ 2671 Cryptography 矩阵乘法+线段树
B - Cryptography Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu Subm ...
- hdu 6155 - Subsequence Count
话说这题比赛时候过的好少,连题都没读TOT 先考虑dp求01串的不同子序列的个数. dp[i][j]表示用前i个字符组成的以j为结尾的01串个数. 如果第i个字符为0,则dp[i][0] = dp[i ...
随机推荐
- uva 12222 Mountain Road
题意: 有一个单行道,两个方向都有车在等待.给出每个车的方向以及到达的时间以及走完这段路所需要的时间. 为了防止车祸,同向两车通过任一点的时间间隔不得小于10s. 求最后一辆车离开时刻的最小值. 思路 ...
- 【Hadoop学习之三】Hadoop全分布式安装
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 hadoop3.1.1 全分布式就是集群,注意配置主机名. ...
- Linux基础命令---查找进程id
pidof pidof可以查找指定名称的进程的pid,将结果送到标准输出.pidof有两种返回值:0,找到至少一个进程:1,没有找到进程.pidof实际上与killall5相同:程序根据调用它的名称进 ...
- Java国际化号码验证方法,国内手机号正则表达式
Java国际化号码验证方法,国内手机号正则表达式 中国电信号段 133.149.153.173.177.180.181.189.199 中国联通号段 130.131.132.145.155.156.1 ...
- [转载]PowerDesigner生成的ORACLE 建表脚本中去掉对象的双引号,设置大、小写
若要将 CDM 中将 Entity的标识符都设为指定的大小写,则可以这么设定: 打开cdm的情况下,进入Tools-Model Options-Naming Convention,把Name和Code ...
- SQL Server双机热备之后项目的FailOver自动连接
SQL Server配置数据库镜像后,可能有朋友们会比较有疑惑,你一下搞两个数据库出来,他们的ip地址都不一样,到时候数据库切换过去了,我的数据库的连接字符串可如何是好?难道还得在代码中去控制是连接哪 ...
- CentOS6.4下邮件服务器搭建
CentOS6.4下邮件服务器搭建 linux下邮件服务器的搭建大致分为三个步骤 准备工作(真实的生产环境下需要) 发送服务器安装及配置 (Postfix) 接收服务器安装及配置(dovecot) ...
- kali linux 压缩文件解压缩命令(包含7z)
tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) ——————————————— .gz 解压1 ...
- Myeclipse错误:Errors occurred during the build. Errors running builder 'DeploymentBuilder' on project 'MyCastBoxAPP' java.lang.NullPointerException
报错起因: 当需要替某项目更名(即右键选定项目后选择Refactor->Rename),点击OK后,发生了中断,提示Undo抑或Abort,无论选择哪个,之后都将弹出以下错误提示框 错误描述: ...
- EDK II之USB协议栈的实现简介
本文旨在简单介绍一下 UEFI中USB协议栈的代码框架: 主要包括: USB主控制器驱动(HCDI:EFI_USB2_HC_PROTOCOL) USB总线驱动(USBDI:EFI_USB_IO_PRO ...