题目描述

你有一个长度为 \(n\) 的数列 \(\{a_n\}\) ,这个数列由 \(0,1\) 组成,进行 \(m\) 个的操作:

\(1\ l\ r\) :把数列区间$ [l,r]$ 内的所有数取反。即 \(0\) 变成 \(1\) ,\(1\) 变成 \(0\) 。

\(2\ l\ r\) :询问数列在区间 \([l, r]\) 内共有多少个本质不同的子序列。

输入输出格式

输入格式:

第一行包含两个整数 \(n,m\),意义如上所述。

接下来一行包含 \(n\) 个数,表示数列 \(\{a_n\}\) 。

接下来 \(m\) 行,每行包含三个数,表示一个操作,操作格式如上所述。

输出格式:

对于每个询问,输出答案模 \(10^{9}+7\) 的结果。

思路

前置技能:

维护一个长度为 \(n\) 的 \(3*3\) 的 \(0/1\) 矩阵序列

  1. 交换区间 \([l,r]\) 中所有矩阵的第一行和第二行

  2. 查询区间 \([l,r]\) 中所有矩阵从左到右乘起来的结果

对于能快速合并的信息我们都可以用线段树来维护

比如和,积,最值, 矩阵乘法, bitset, hash值,线性基

还需要一个矩阵的结论:

对于 3*3 的 0/1 矩阵来说 两矩阵的第一二行交换,他们的乘积的第一二行也交换

所以可以对于交换的区间打 tag,用线段树维护

本题思路

考虑本质不同的子序列怎么求:

设 f(i,0) 表示i号位置以前的以0结尾的本质不同的子序列数目

设 f(i,1) 表示i号位置以前的以1结尾的本质不同的子序列数目

转移方程 :

如果 i 号位置是 0 ,\(f(i,0) = f(i-1,0) + f(i-1,1) + 1 ; f(i, 1) = f(i-1, 1)\)

如果 i 号位置是 1 ,\(f(i,1) = f(i-1,0) + f(i-1,1) + 1 ; f(i, 0) = f(i-1, 0)\)

用矩阵加速,可得:

观察矩阵可得,对区间内序列取反,可以转化为把矩阵的前两行,前两列交换

可用线段树来维护

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
using namespace std;
const int MOD = 1e9 + 7;
int init() {
int rv = 0, fh = 1;
char c = getchar();
while(c <'0' || c > '9') {
if(c == '-') fh = -1;
c=getchar();
}
while(c >= '0' && c <= '9') {
rv=(rv<<1) + (rv<<3) + c- '0';
c = getchar();
}
return fh * rv;
}
const int MAXN=100005;
struct Matrix{
ll num[3][3];
int col;
Matrix() {
col = 0;
memset(num,0,sizeof(num));
}
void build(bool f){
col=3;
if(f) {
num[0][0] = num[0][1] = num[1][1] = num[2][1] = num[2][2] = 1;
}else {
num[0][0] = num[1][0] = num[2][0] = num[1][1] = num[2][2] = 1;
}
}
Matrix operator * (const Matrix &a) {
Matrix ans;
ans.col = col;
for(int i = 0 ; i < col ; i++) {
for(int j = 0 ; j < 3 ; j++) {
for(int k = 0 ; k < 3 ; k++) {
(ans.num[i][j] += num[i][k] * a.num[k][j]) %= MOD;
}
}
}
return ans;
}
void reserve() {
for(int i = 0 ; i < 3 ; i++) {
swap(num[0][i],num[1][i]);
}
for(int i = 0 ; i <3 ; i++) {
swap(num[i][0], num[i][1]);
}
}
void print() {
for(int i = 0 ; i<=col ;i++) {
for(int j = 0 ; j < 3 ; j++) {
printf("%d ",num[i][j]);
}
cout<<endl;
}
}
};
struct SGT{
Matrix sum[MAXN<<2];
bool tag[MAXN<<2];
void PushUp(int rt) {
sum[rt] = sum[rt<<1] * sum[rt<<1|1];
}
void build(int l, int r,int rt) {
if(l==r) {
bool f=init();
sum[rt].build(f);
return;
}
int mid = (l + r) >>1;
build(lson);
build(rson);
PushUp(rt);
}
void PushDown(int rt) {
if(tag[rt]) {
tag[rt<<1] = !tag[rt<<1] ;
tag[rt<<1|1] = !tag[rt<<1|1];
sum[rt<<1].reserve();
sum[rt<<1|1].reserve();
tag[rt]=0;
}
}
void Update(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
tag[rt]=!tag[rt];
sum[rt].reserve();
return;
}
PushDown(rt);
int mid = (l + r) >>1;
if(L <= mid) Update(L, R, lson);
if(mid < R) Update(L, R, rson);
PushUp(rt);
}
Matrix Query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return sum[rt];
}
PushDown(rt);
int mid = (l + r) >>1;
Matrix ans;
ans.col = 3;
ans.num[0][0] = ans.num[1][1] = ans.num[2][2] = 1;//ans.print();
if(L <= mid) ans = ans * Query(L, R, lson);
if(mid < R) ans = ans * Query(L, R, rson);
PushUp(rt);
return ans;
}
}sgt;
int n,m;
int main() {
freopen("in.txt", "r", stdin);
n=init();m=init();
sgt.build(1,n,1);
for(int i = 1 ; i <= m ; i++) {
int t = init(), l = init(), r = init();
if(t == 1) {
sgt.Update(l, r, 1, n, 1);
}else {
Matrix ans;
ans.col = 1;ans.num[0][2] = 1;
ans = ans * sgt.Query(l, r, 1, n, 1);
//sgt.Query(l, r, 1, n, 1).print();
printf("%lld\n",(ans.num[0][0] + ans.num[0][1])%MOD);
}
}
fclose(stdin);
return 0;
}

洛谷 [T21776] 子序列的更多相关文章

  1. 洛谷T21776 子序列

    题目描述 你有一个长度为 nn 的数列 \{a_n\}{an​} ,这个数列由 0,10,1 组成,进行 mm 个的操作: 1~l~r1 l r :把数列区间 [l, r][l,r] 内的所有数取反. ...

  2. 洛谷P1410 子序列

    题目描述 给定一个长度为N(N为偶数)的序列,问能否将其划分为两个长度为N/2的严格递增子序列, 输入输出格式 输入格式: 若干行,每行表示一组数据.对于每组数据,首先输入一个整数N,表示序列的长度. ...

  3. 洛谷 P1410 子序列(DP)

    这题的题解的贪心都是错误的...正解应该是个DP 考虑有哪些有关的条件:两个序列的当前长度, 两个序列的末尾数, 把这些都压进状态显然是会GG的 考虑两个长度加起来那一位的数一定是其中一个序列的末尾, ...

  4. 洛谷 P1439 【模板】最长公共子序列

    \[传送门啦\] 题目描述 给出\(1-n\)的两个排列\(P1\)和\(P2\),求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数\(n\), 接下来两行,每行为\(n\)个数,为 ...

  5. 洛谷CF264D Colorful Stones(子序列匹配,思维)

    洛谷题目传送门 神仙思维题. 对于两个字符串的匹配问题,似乎之前蒟蒻写的HAOI2010最长公共子序列题解中提到的建网格图模型是一种套路? 给一个稍微强一点的样例(把字母换成了ABC) AABCB B ...

  6. 洛谷P2516 [HAOI2010]最长公共子序列(LCS,最短路)

    洛谷题目传送门 一进来就看到一个多月前秒了此题的ysn和YCB%%% 最长公共子序列的\(O(n^2)\)的求解,Dalao们想必都很熟悉了吧!不过蒟蒻突然发现,用网格图貌似可以很轻松地理解这个东东? ...

  7. 洛谷1439:最长公共子序列(nlogn做法)

    洛谷1439:最长公共子序列(nlogn做法) 题目描述: 给定两个序列求最长公共子序列. 这两个序列一定是\(1\)~\(n\)的全排列. 数据范围: \(1\leq n\leq 10^5\) 思路 ...

  8. 最长公共子序列问题(LCS) 洛谷 P1439

    题目:P1439 [模板]最长公共子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 关于LCS问题,可以通过离散化转换为LIS问题,于是就可以使用STL二分的方法O(nlogn ...

  9. 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】

    题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...

随机推荐

  1. 推荐一个markdown格式转html格式的开源JavaScript库

    这个markdown格式转html格式的开源JavaScript库在github上的地址: https://github.com/millerblack/markdown-js 从markdown 格 ...

  2. 分布式锁----浅析redis实现

    引言大概两个月前小伙伴问我有没有基于redis实现过分布式锁,之前看redis的时候知道有一个RedLock算法可以实现分布式锁,我接触的分布式项目要么是github上开源学习的,要么是小伙伴们公司项 ...

  3. linux下使用OpenCV的一些问题

    完整正确的代码如下: import cv2 import numpy as np image = cv2.imread('Pictures/a.png') cv2.imshow('original_i ...

  4. QT +样式表

    学习样式表的目的:可以设计出好看的控件.(比如可以给一些按钮设计成好看的图片) QT 样式表的思想很大程度上是来自于HTML的层叠式样式表(CSS),通过调用QWidget->setStyleS ...

  5. springboot-i18n国际化

    简介 In computing, internationalization and localization are means of adapting computer software to di ...

  6. Android之通过adb shell 模拟器 error: more than one device and emulator 改ip dns

    error: more than one device and emulator 如果出现上面那种情况 请关闭  ide 输入下面的  再次重新启动 模拟器 如果实际上只有一个设备或模拟器,并且查到有 ...

  7. Jarvis OJ-Smashes

    栈溢出之利用-stack-chk-fail from pwn import * old_flag_addr = 0x600d20 new_flag_addr = 0x400d20 #p = proce ...

  8. shell脚本,怎么实现每次新开一个shell都输出一个提示语?

    [root@localhost wyb]# cat test.sh echo -e "\033[32mhello,This is wangyuebo's shell\033[0m" ...

  9. Hdu 3177 (贪心)

    题目大意: 山洞的体积为\(v\) 第\(i\)个物品放在山洞里会占据\(a_i\)的空间,在搬运过程中至少需要\(b_i\)的空间 问能不能把所有物品都放下 贪心题.比较难看出贪心,但是从无顺序要求 ...

  10. opencast 视频捕获代理 pyCA安装和功能实现

    pyCA安装过程: 36 git clone https://github.com/opencast/pyCA.git 37 cd pyCA/ 41 yum install python-pycurl ...