hdu6155
hdu6155
题意
给出一个只由 \(01\) 组成的字符串 \(s\),有两种操作:
- 翻转区间 \([l, r]\)
- 查询区间 \([l, r]\) 有多少不同的子串
分析
首先考虑怎么统计区间有多少不同的子串。
\(dp[i][0]\) 表示以 \(s[i]=0\) 结尾的字符串的个数,\(dp[i][1]\) 同理。
若 \(s[i]=0\),有状态转移方程:\(dp[i + 1][0] = dp[i][0] + dp[i][1] + 1\),\(dp[i+1][1]=dp[i][1]\)。
\(dp[i][1]\) 同理。
那么答案就是 \(dp[len][0]+dp[len][1]\) 。
可以用矩阵递推:
\]
又矩阵存在结合律,所以一段区间的查询,只需要求右边一系列乘数的乘积即可。
我们可以使用线段树,去区间求积。
对于翻转操作,先将第一列和第二列交换,再将第一行和第二行交换。因为 \(01\) 是相对的,只需要交换对应的值即可。
可以在线段树中标记是否需要翻转某个区间。
看完题解写完后,猛然发现,这竟是一道线段树区间更新区间求和的“模板题”。
code
#include<bits/stdc++.h>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
struct Matrix {
ll mat[3][3];
void init() {
memset(mat, 0, sizeof mat);
}
Matrix operator *(Matrix A) {
Matrix B;
B.init();
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
for(int k = 0; k < 3; k++) {
B.mat[i][j] += mat[i][k] * A.mat[k][j];
}
B.mat[i][j] %= MOD;
}
}
return B;
}
};
char s[MAXN];
int flip[MAXN << 2];
Matrix sum[MAXN << 2];
inline void magic(Matrix& A) { // 先将第一列和第二列交换,再将第一行和第二行交换
for(int i = 0; i < 3; i++) swap(A.mat[i][0], A.mat[i][1]);
for(int i = 0; i < 2; i++) swap(A.mat[0][i], A.mat[1][i]);
}
inline void pushUp(int rt) {
sum[rt] = sum[rt << 1] * sum[rt << 1 | 1];
}
inline void pushDown(int rt) {
if(flip[rt]) {
flip[rt << 1] ^= flip[rt];
flip[rt << 1 | 1] ^= flip[rt];
magic(sum[rt << 1]);
magic(sum[rt << 1 | 1]);
flip[rt] = 0;
}
}
void build(int l, int r, int rt) {
flip[rt] = 0;
if(l == r) {
Matrix& A = sum[rt];
if(s[l] == '0') {
A = Matrix{1, 0, 0, 1, 1, 0, 1, 0, 1};
} else {
A = Matrix{1, 1, 0, 0, 1, 0, 0, 1, 1};
}
return;
}
int m = (l + r) / 2;
build(lson);
build(rson);
pushUp(rt);
}
void update(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
flip[rt] ^= 1;
magic(sum[rt]);
return;
}
pushDown(rt);
int m = (l + r) / 2;
if(L <= m) update(L, R, lson);
if(R > m) 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 m = (l + r) / 2;
Matrix A;
A.init();
for(int i = 0; i < 3; i++) A.mat[i][i] = 1;
if(L <= m) A = A * query(L, R, lson);
if(R > m) A = A * query(L, R, rson);
pushUp(rt);
return A;
}
//适用于正整数
template <class T>
inline void scan_d(T &ret) {
char c; ret=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
int main() {
int T;
scanf("%d", &T);
int n, q;
while(T--) {
scanf("%d%d", &n, &q);
scanf("%s", s + 1);
build(1, n, 1);
while(q--) {
int type, l, r;
scan_d(type); scan_d(l); scan_d(r);
if(type == 1) update(l, r, 1, n, 1);
else {
Matrix A = query(l, r, 1, n, 1);
printf("%lld\n", (A.mat[2][0] + A.mat[2][1]) % MOD);
}
}
}
return 0;
}
hdu6155的更多相关文章
- [HDU6155]Subsequence Count(线段树+矩阵)
DP式很容易得到,发现是线性递推形式,于是可以矩阵加速.又由于是区间形式,所以用线段树维护. https://www.cnblogs.com/Miracevin/p/9124511.html 关键在于 ...
- [HDU6155]Subsequence Count
题目大意: 给定一个01序列,支持以下两种操作: 1.区间反转: 2.区间求不同的子序列数量. 思路: 首先我们考虑区间反转,这是一个经典的线段树操作. 接下来考虑求不同的子序列数量,在已知当前区间的 ...
- 洛谷T21776 子序列
题目描述 你有一个长度为 nn 的数列 \{a_n\}{an} ,这个数列由 0,10,1 组成,进行 mm 个的操作: 1~l~r1 l r :把数列区间 [l, r][l,r] 内的所有数取反. ...
随机推荐
- Walk 解题报告
Walk 题目描述 给定一棵 \(n\) 个节点的树,每条边的长度为 \(1\),同时有一个权值\(w\).定义一条路径的权值为路径上所有边的权值的最大公约数.现在对于任意 \(i \in [1,n] ...
- 群联MPALL(Rel) 7F V5.03.0A-DL07量产工具 PS2251-07(PS2307)
前言:U盘被写保护,真的很醉人啊~~ 群联MPALL是一款群联PS2251系列主控量产修复工具,本版本支持PS2251-67.PS2251-68.PS2251-02.PS2251-03.PS ...
- MyBatis的SQL语句映射文件详解(二)----增删改查
1.select语句 public List<User> findUser() { // TODO Auto-generated method stub List users= ( ...
- (转)C/S 与 B/S 区别
感谢:http://www.cnblogs.com/xiaoshuai/archive/2010/05/25/1743741.html C/S结构,即Client/Server(客户机/服务器)结构, ...
- L2-002. 链表去重---模拟
https://www.patest.cn/contests/gplt/L2-002 L2-002. 链表去重 时间限制 300 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 ...
- 我在开发中所遇到的iOS7新特性以及iOS7与iOS6的适配问题总结
⓵UIImageView 1. // iOS7添加的对图像颜色处理的功能,过滤颜色的功能 2. _imageView.tintColor = [UIColor blueColor]; 3. //重 ...
- Linux下程序对拍_C++ (付费编号1001)
本博客为精品博客,涉及利益问题,严禁转载,违者追究法律责任 一.对拍背景 对拍是一种十分实用的检查程序正确性的手段,在比赛时广泛使用 我们一般对拍两个程序,一个是自己不确定正确性的高级算法,另一个一般 ...
- javascript的阻塞机制
javascript的阻塞机制 浏览器在执行javascript代码时,不能同时做其它事情,当遇到javascript时,浏览器会下载js文件,解析并执行该文件,而在这期间页面的渲染是完全被阻塞的,因 ...
- mysql 表的类型
MySQL 数据表主要支持六种类型 ,分别是:BDB.HEAP.ISAM.MERGE.MYISAM.InnoBDB. 这六种又分为两类,一类是”事务安全型”(transaction-safe),包括B ...
- 图像转换为二进制文件存入DSP6748
本文为原创作品,转载请注明出处 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和http://www.cnblogs.com/xujianqing/ 这篇博客主 ...