题目描述

你有一个长度为 \(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. Caused by: java.lang.NoClassDefFoundError: com/sun/tools/javac/util/List at

    折腾了一下的时间,都没有找到解决的方案,在网上搜了一下答案都是让清理编译环境和重新打包之类的.就这样折腾一下,还没有解决问题.之所以会抛出找不到类的问题,需要排查你使用这个包的类是否存在,存在之后 查 ...

  2. LintCode 30插入区间

    问题 给出一个无重叠的按照区间起始端点排序的区间列表. 在列表中插入一个新的区间,你要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间). 样例 插入区间[2, 5] 到 [[1,2], ...

  3. 51nod 算法马拉松17 解题报告 以后不能赛中写题解(查逐梦者抄袭本人代码...

    B题(数学题: 问(1+sqrt(2)) ^n  能否分解成 sqrt(m) +sqrt(m-1)的形式  如果可以 输出 m%1e9+7 否则 输出no n<=1e18 刚看题没思路 暴力一下 ...

  4. 爬虫5_python2_使用 Beautiful Soup 解析数据

    使用 Beautiful Soup 解析数据(感谢东哥) 有的小伙伴们对写正则表达式的写法用得不熟练,没关系,我们还有一个更强大的工具,叫Beautiful Soup,有了它我们可以很方便地提取出HT ...

  5. CentOS 7.0关闭防火墙

    .关闭firewall: systemctl stop firewalld.service #停止firewall systemctl disable firewalld.service #禁止fir ...

  6. UNIX 进程间通讯(IPC)概念(Posix,System V IPC)

     IPC(Inter-Process Communication,进程间通讯)可以有三种信息共享方式(随文件系统,随内核,随共享内存).(当然这里虽然说是进程间通讯,其实也是可以和线程相通的). 相对 ...

  7. syslog命令

    更多请关注 Linux命令大全 syslog 介绍 syslog是Linux系统默认的日志守护进程.默认的syslog配置文件是/etc/syslog.conf文件.程序,守护进程和内核提供了访问系统 ...

  8. Google实践中总结的Python规范,get了吗?

    好的代码风格,给人舒服的感觉,今天介绍一下谷歌的Python风格规范 1 分号 不要在行尾加分号, 也不要用分号将两条命令放在同一行. 2 行长度 每行不超过80个字符:不要使用反斜杠连接行.Pyth ...

  9. Day10文件内指针移动和函数

    强调:只有t模式下的read(n),n代表字符个数,除此以外都是以字节为单位 ,例如f.read(4)读出4个字符 控制文件内指针的移动:f.seek()以字节为单位 f.tell()文件开头为准,当 ...

  10. Many-to-one

    创建模型 from django.db import models class Reporter(models.Model): first_name = models.CharField(max_le ...