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 ...
随机推荐
- Eclipse中tomcat更改部署路径 deply path
默认是部署在项目元数据文件夹.metadata文件夹下,需要更改到tomcat/webapps目录下 Eclipse中tomcat service设置 选择window ----show view-- ...
- UVA 11100 The Trip, 2007 (贪心)
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
- C#——WebApi 接口参数传参详解
本篇打算通过get.post.put.delete四种请求方式分别谈谈基础类型(包括int/string/datetime等).实体.数组等类型的参数如何传递. 一.get请求 对于取数据,我们使用最 ...
- 前端页面报net::ERR_CONNECTION_RESET错误的原因
本机和测试环境都是OK的.但是一到线上就报错:可能原因总结如下: 1 可能是服务器限制了文件上传的权限. 解决方法:开通了文件上传权限. 2 也许导致这种错误的方式有很多,可能是因为post请求时提交 ...
- 理解Sql Server 事务隔离层级(Transaction Isolation Level)
关于Sql Server 事务隔离级别,百度百科是这样描述的 隔离级别:一个事务必须与由其他事务进行的资源或数据更改相隔离的程度.隔离级别从允许的并发副作用(例如,脏读或虚拟读取)的角度进行描述. 隔 ...
- Django之404、500、400错误处理
要自定义处理url请求错误需要进行三步操作:主要错误有: 404错误:page not found视图 500错误:server error视图 400错误:bad request视图 以404错误为 ...
- Java中五种遍历HashMap的方式
import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class Java8Templat ...
- ElasticSearch(二)CentOs6.4下安装ElasticSearch
一.准备工作 Elastic 需要 Java 8 环境.如果你的机器还没安装 Java,先需要安装java环境,同时还注意要保证环境变量JAVA_HOME正确设置. 链接:https://pan.ba ...
- The address where a.out.debug has been loaded is missing以及No symbol "*" in current context原因与解决方法
最近,在debug core的时候,发现p 变量的时候提示“No symbol "*" in current context”,我们的代码使用-g编译的,经查有可能是下列几个原因或 ...
- 更改 centos 7的源为 阿里源
阿里源的网址在这里:http://mirrors.aliyun.com/repo/ 一.进入源文件存放目录 cd /etc/yum.repos.d 二.安装基本源: 1.如果要备份原来的源文件 sud ...