洛谷T21776 子序列
题目描述
你有一个长度为 nn 的数列 \{a_n\}{an} ,这个数列由 0,10,1 组成,进行 mm 个的操作:
1~l~r1 l r :把数列区间 [l, r][l,r] 内的所有数取反。即 00 变成 11 ,11 变成 00 。
2~l~r2 l r :询问数列在区间 [l, r][l,r] 内共有多少个本质不同的子序列。
输入输出格式
输入格式:
第一行包含两个整数 n, mn,m ,意义如上所述。
接下来一行包含 nn 个数,表示数列 \{a_n\}{an} 。
接下来 mm 行,每行包含三个数,表示一个操作,操作格式如上所述。
输出格式:
对于每个询问,输出答案模 10^9 + 7109+7 的结果。
输入输出样例
说明
对于 10 \%10% 的数据,1 \leq n, m \leq 10^21≤n,m≤102 。
对于 30 \%30% 的数据,1 \leq n, m \leq 10^31≤n,m≤103 。
对于 100 \%100% 的数据,1 \leq n, m \leq 10^51≤n,m≤105 。
这道题同HDU6155(只不过我在HDU上T飞了)
首先我们考虑一下暴力怎么写
dp[i][1]表示到第$i$个位置,以$1$结尾,本质不同的子序列
dp[i][0]表示到第$i$个位置,以$0$结尾,本质不同的子序列
转移的时候,假设第$i$个字符是1
那么对它有贡献的是以前以$0$结尾的子序列,以及以前以$1$结尾的子序列,以及空串
那么此时
$dp[i][1]=dp[i-1][0]+dp[i-1][1]+1$
$dp[i][0]=dp[i-1][0]$
当第$i$个字符是$0$的时候同理,不难得到
$dp[i][1]=dp[i-1][1]$
$dp[i][0]=dp[i-1][0]+dp[i-1][1]+1$
大家有没有发现一件事情?
这个dp的转移是递推!也就是说我们可以用矩阵乘法来加速!
而矩阵乘法可以用线段树来维护!
它的矩阵为

对于操作1的话,先交换要改变的矩阵的第一行和第二行,再交换要改变的矩阵的第一列和第二列
至于为什么?这个可以转移之间的关系入手,也可以直接找规律
这样就实现了两个矩阵的转换
另外还有一点、
对于结果矩阵,我们只会用到[3][1]和[3][2]这两项(分别代表dp[n][1],dp[n][0])
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long int
#define ls k<<1
#define rs k<<1|1
using namespace std;
const int MAXN=1e6+;
const int mod=1e9+;
inline int read()
{
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
char c[MAXN];
struct Matrix
{
LL mat[][];
Matrix(){memset(mat,,sizeof(mat));}
};
struct node
{
int l,r,w;
bool f;
Matrix m;
}T[MAXN];
Matrix zero,one,HHHHH;
Matrix rev(Matrix &a)
{
for(LL i=;i<=;i++) swap(a.mat[][i],a.mat[][i]);
for(LL i=;i<=;i++) swap(a.mat[i][],a.mat[i][]);
}
Matrix MatrixMul(Matrix a,Matrix b)
{
Matrix c;
for(LL k=;k<=;k++)
for(LL i=;i<=;i++)
for(LL j=;j<=;j++)
c.mat[i][j]=(c.mat[i][j]+(a.mat[i][k]*b.mat[k][j])%mod )%mod;
return c;
}
void update(int k)
{
T[k].m=MatrixMul(T[ls].m,T[rs].m);
}
void pushdown(int k)
{
if(T[k].f)
{
T[ls].f^=;T[rs].f^=;
rev(T[ls].m);rev(T[rs].m);
T[k].f=;
}
}
void Build(int k,int ll,int rr)
{
T[k].l=ll;T[k].r=rr;T[k].f=;
if(ll==rr)
{
if(c[ll]=='') T[k].m=zero;
else T[k].m=one;
return ;
}
int mid=ll+rr>>;
Build(ls,ll,mid);
Build(rs,mid+,rr);
update(k);
}
void IntervalChange(int k,int ll,int rr)
{
if(ll<=T[k].l&&T[k].r<=rr)
{
T[k].f^=;
rev(T[k].m);
return ;
}
pushdown(k);
int mid=T[k].l+T[k].r>>;
if(ll<=mid) IntervalChange(ls,ll,rr);
if(rr>mid) IntervalChange(rs,ll,rr);
update(k);
}
Matrix IntervalAsk(int k,int ll,int rr)
{
Matrix ans=HHHHH;
if(ll<=T[k].l&&T[k].r<=rr)
{
ans=T[k].m;
return ans;
}
pushdown(k);
LL mid=T[k].l+T[k].r>>;
if(ll<=mid)
ans=MatrixMul(IntervalAsk(ls,ll,rr),ans);
if(rr>mid)
ans=MatrixMul(ans,IntervalAsk(rs,ll,rr));
return ans;
}
int main()
{
int N,M;
zero.mat[][]=zero.mat[][]=zero.mat[][]=zero.mat[][]=zero.mat[][]=;
one.mat[][]=one.mat[][]=one.mat[][]=one.mat[][]=one.mat[][]=;
HHHHH.mat[][]=HHHHH.mat[][]=HHHHH.mat[][]=;
int T;
T=;
while(T--)
{
N=read();M=read();
scanf("%s",c+);
Build(,,N);
while(M--)
{
int opt=read(),l=read(),r=read();
if(opt==)
{
IntervalChange(,l,r);
}
else if(opt==)
{
Matrix ans=IntervalAsk(,l,r);
printf("%lld\n", (ans.mat[][]+ans.mat[][])%mod );
}
}
}
return ;
}
洛谷T21776 子序列的更多相关文章
- 洛谷 [T21776] 子序列
题目描述 你有一个长度为 \(n\) 的数列 \(\{a_n\}\) ,这个数列由 \(0,1\) 组成,进行 \(m\) 个的操作: \(1\ l\ r\) :把数列区间$ [l,r]$ 内的所有数 ...
- 洛谷P1410 子序列
题目描述 给定一个长度为N(N为偶数)的序列,问能否将其划分为两个长度为N/2的严格递增子序列, 输入输出格式 输入格式: 若干行,每行表示一组数据.对于每组数据,首先输入一个整数N,表示序列的长度. ...
- 洛谷 P1410 子序列(DP)
这题的题解的贪心都是错误的...正解应该是个DP 考虑有哪些有关的条件:两个序列的当前长度, 两个序列的末尾数, 把这些都压进状态显然是会GG的 考虑两个长度加起来那一位的数一定是其中一个序列的末尾, ...
- 洛谷 P1439 【模板】最长公共子序列
\[传送门啦\] 题目描述 给出\(1-n\)的两个排列\(P1\)和\(P2\),求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数\(n\), 接下来两行,每行为\(n\)个数,为 ...
- 洛谷CF264D Colorful Stones(子序列匹配,思维)
洛谷题目传送门 神仙思维题. 对于两个字符串的匹配问题,似乎之前蒟蒻写的HAOI2010最长公共子序列题解中提到的建网格图模型是一种套路? 给一个稍微强一点的样例(把字母换成了ABC) AABCB B ...
- 洛谷P2516 [HAOI2010]最长公共子序列(LCS,最短路)
洛谷题目传送门 一进来就看到一个多月前秒了此题的ysn和YCB%%% 最长公共子序列的\(O(n^2)\)的求解,Dalao们想必都很熟悉了吧!不过蒟蒻突然发现,用网格图貌似可以很轻松地理解这个东东? ...
- 洛谷1439:最长公共子序列(nlogn做法)
洛谷1439:最长公共子序列(nlogn做法) 题目描述: 给定两个序列求最长公共子序列. 这两个序列一定是\(1\)~\(n\)的全排列. 数据范围: \(1\leq n\leq 10^5\) 思路 ...
- 最长公共子序列问题(LCS) 洛谷 P1439
题目:P1439 [模板]最长公共子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 关于LCS问题,可以通过离散化转换为LIS问题,于是就可以使用STL二分的方法O(nlogn ...
- 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】
题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...
随机推荐
- Nginx 安装 自用
hostnamectl set-hostname nginx systemctl stop firewalld.service systemctl disable firewalld.service ...
- useradd: cannot open /etc/passwd
[root@ftp ~]# useradd -g ftp -s/sbin/nologin liwmuseradd: cannot open /etc/passwd [root@ftp ~]# user ...
- UI布局【转】
转载自: https://www.cnblogs.com/wangdaijun/p/5519459.html https://www.jianshu.com/p/f781c40df57c Good U ...
- Android APP弱网测试问题和解决分析
最近做了一次移动APP的弱网和中断测试,接下来分享一下遇到的一些问题: 1.现象:用户登录应用时下载初始化数据,下载过程中因网速太慢点击取消并重新登录,数据初始化完成后出现重复,造成数据不一致. 原因 ...
- Node.js使用cnpm
npm是Node.js中维护第三方库.模块的工具,可是国外的速度非常悲剧,这里有一个中国的源cnpm. http://cnpmjs.org/ 须要在命令行中执行 npm install -g cnpm ...
- SVN配置以及自己主动部署到apache虚拟文件夹
SVN配置以及自己主动部署到apache虚拟文件夹 一.VisualSVN server 服务端和TortoiseSVNclient下载 VisualSVN下载:http://subversion.a ...
- 查看CPU是几核
命令1 (查看有几个CPU):cat /proc/cpuinfo |grep "physical id"|sort |uniq|wc -l 命令2 (每个CPU几核):cat /p ...
- Android 流量分析 tcpdump & wireshark
APP竞争已经白热化了,控制好自己Android应用的流量能够给用户一个良好的用户体验噢,给用户多一个不卸载的理由. Android 怎样进行流量分析?用好tcpdump & wireshar ...
- WAF——针对Web应用发起的攻击,包括但不限于以下攻击类型:SQL注入、XSS跨站、Webshell上传、命令注入、非法HTTP协议请求、非授权文件访问等
核心概念 WAF Web应用防火墙(Web Application Firewall),简称WAF. Web攻击 针对Web应用发起的攻击,包括但不限于以下攻击类型:SQL注入.XSS跨站.Websh ...
- zzulioj--1804--ZY学长的密码(字符串)
1804: ZY学长的密码 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 140 Solved: 53 SubmitStatusWeb Board ...