Problem Description
Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string.
There are two types of queries:
1. Flipping the bits (i.e., changing all 1 to 0 and 0 to 1) between l and r (inclusive).
2. Counting the number of distinct subsequences in the substring S[l,...,r].
 
Input
The first line contains an integer T, denoting the number of the test cases.
For each test, the first line contains two integers N and Q.
The second line contains the string S.
Then Q lines follow, each with three integers type, l and r, denoting the queries.

1≤T≤5
1≤N,Q≤105
S[i]∈{0,1},∀1≤i≤N
type∈{1,2}
1≤l≤r≤N

 
Output
For each query of type 2, output the answer mod (109+7) in one line.
 
首先考虑怎么求一个01串有多少种不同的子序列
dp[i][0]表示考虑到第i位时以0结尾的不同的子序列个数
dp[i][1]表示考虑到第i位时以1结尾的不同的子序列个数
若第i+1位为1,则有:
以01为结尾的子序列个数为dp[i][0]
以11为结尾的子序列个数为dp[i][1]
只有一个1的子序列个数为1
以0为结尾的子序列个数为dp[i][0]
 
以上4种情况统计了考虑到i+1处时所有的子序列
于是有 dp[i+1][1]=dp[i][0]+dp[i][1]+1
   dp[i+1][0]=dp[i][0]
            (1  1  0
(dp[i][0],dp[i][1],1)* 0  1  0   =(dp[i+1][0],dp[i+1][1],1)
             0  1  1)
 记为A矩阵。
若i+1位为0同理有:    
    dp[i+1][1]=dp[i][0]
    dp[i+1][0]=dp[i][0]+dp[i][1]+1
    对应矩阵为(记为B矩阵)
          1  0  0                          
          1  1  0                          
          1  0  1                          
其次考虑优化的问题。将以上的两种转移视为矩阵,用线段树维护矩阵的乘积即可。
 
对于将所有0换成1,1换成0的操作而言,等价于将所有A矩阵换成B,B换成A,而A和B通过交换1,2行及1,2列可互相转换,或者说,乘以初等矩阵Fs,t  ,该矩阵的逆为自身。(记其为F)

                                                            0  1  0     
                                                            1  0  0

  

                                                          0  0  1
 
 
于是有FAFFAF……FBF……=FAAB……F,或者说,将大量0换成1,1换成0的时候只需要在乘积最外面进行一次交换1,2行与1,2列的操作。
 
然而。。仍然TLE..估计是被卡了常数。心塞。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int N,Q;
const long long int mo=1e9+;
char s[];
int lazy[<<];
struct Matrix{
int n,m;
long long a[][];
Matrix (){clear();}
void clear(){
n=m=;
memset(a,,sizeof(a));
}
Matrix operator *(const Matrix &b) const{
Matrix tmp;
for (int i=;i<n;++i)
for (int j=;j<b.m;++j)
for (int k=;k<m;++k)
tmp.a[i][j]=(tmp.a[i][j]+a[i][k]*b.a[k][j])%mo;
return tmp;
}
};
Matrix A0,A1,E;
Matrix cnt[<<];
inline void init()
{
A0.a[][]=,A0.a[][]=,A0.a[][]=;
A0.a[][]=,A0.a[][]=,A0.a[][]=;
A0.a[][]=,A0.a[][]=,A0.a[][]=; A1.a[][]=,A1.a[][]=,A1.a[][]=;
A1.a[][]=,A1.a[][]=,A1.a[][]=;
A1.a[][]=,A1.a[][]=,A1.a[][]=; E.a[][]=,E.a[][]=,E.a[][]=;
E.a[][]=,E.a[][]=,E.a[][]=;
E.a[][]=,E.a[][]=,E.a[][]=;
}
inline void Pushup(int rt)
{
cnt[rt]=cnt[rt<<]*cnt[rt<<|];
}
inline void build(int l,int r,int rt)
{
if(l==r)
{
if(s[l-]-''==)
{
cnt[rt]=A0;
}
else cnt[rt]=A1;
return;
}
int m=(l+r)>>;
build(lson);
build(rson);
Pushup(rt);
}
inline void change(Matrix &X)
{
swap(X.a[][],X.a[][]);
swap(X.a[][],X.a[][]);
swap(X.a[][],X.a[][]);
} inline void pushdown(int rt)
{
if(lazy[rt])
{
change(cnt[rt<<]);
change(cnt[rt<<|]);
lazy[rt<<]^=;
lazy[rt<<|]^=;
lazy[rt]=;
}
}
inline void update(int a,int b,int l,int r,int rt)
{
if(l>=a&&r<=b)
{
change(cnt[rt]);
lazy[rt]^=;
return;
}
pushdown(rt);
int m=(l+r)>>;
if(a<=m) update(a,b,lson);
if(b>m) update(a,b,rson);
Pushup(rt);
}
inline void Input()
{
scanf("%d%d",&N,&Q);
scanf("%s",s);
}
inline Matrix query(int a,int b,int l,int r,int rt)
{
if(l>=a&&r<=b) return cnt[rt];
pushdown(rt);
Matrix t1=E,t2=E;
int m=(r+l)>>;
if(a<=m) t1=query(a,b,lson);
if(b>m) t2=query(a,b,rson);
return t1*t2;
}
int main()
{
//freopen("in.txt","r",stdin);
int T,type,l,r;
scanf("%d",&T);
init();
rep(t,,T)
{
Input();
build(,N,);
rep(i,,Q)
{
scanf("%d%d%d",&type,&l,&r);
if(type==)
{
update(l,r,,N,);
// rep(j,1,2*N) printf("i=%d dp%d=%lld\n",i,j,(cnt[j].a[2][0]+cnt[j].a[2][1])%mo);
}
else
{
Matrix tmp;
tmp=query(l,r,,N,);
printf("%lld\n",(tmp.a[][]+tmp.a[][])%mo);
}
}
}
return ;
}
 
代码如下:

Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵的更多相关文章

  1. DP+线段树维护矩阵(2019牛客暑期多校训练营(第二场))--MAZE

    题意:https://ac.nowcoder.com/acm/contest/882/E 给你01矩阵,有两种操作:1是把一个位置0变1.1变0,2是问你从第一行i开始,到最后一行j有几种走法.你只能 ...

  2. [动态dp]线段树维护转移矩阵

    背景:czy上课讲了新知识,从未见到过,总结一下. 所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法. 这类题目分为如下三个步骤:(都是对于常系数齐次递推问题) 1先不考虑修改,不考虑区 ...

  3. Codeforces 750E - New Year and Old Subsequence(线段树维护矩阵乘法,板子题)

    Codeforces 题目传送门 & 洛谷题目传送门 u1s1 我做这道 *2600 的动力是 wjz 出了道这个套路的题,而我连起码的思路都没有,wtcl/kk 首先考虑怎样对某个固定的串计 ...

  4. Codeforces 1368H - Breadboard Capacity(最小割+线段树维护矩阵乘法)

    Easy version:Codeforces 题面传送门 & 洛谷题面传送门 Hard version:Codeforces 题面传送门 & 洛谷题面传送门 首先看到这种从某一种颜色 ...

  5. hdu 5068 线段树维护矩阵乘积

    http://acm.hdu.edu.cn/showproblem.php?pid=5068 题意给的略不清晰 m个询问:从i层去j层的方法数(求连段乘积)或者修改从x层y门和x+1层z门的状态反转( ...

  6. 线段树维护矩阵【CF718C】 Sasha and Array

    Description 有一个长为\(n\)的数列\(a_{1},a_{2}...a_{n}\),你需要对这个数列维护如下两种操作: \(1\space l \space r\space x\) 表示 ...

  7. CF718C Sasha and Array(线段树维护矩阵)

    题解 (不会矩阵加速的先去学矩阵加速) 反正我想不到线段树维护矩阵.我太菜了. 我们在线段树上维护一个区间的斐波那契的列矩阵的和. 然后询问时提取每个符合题意列矩阵的答案项(不是列矩阵存了两项吗,一个 ...

  8. HDU 6155 Subsequence Count 线段树维护矩阵

    Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Oth ...

  9. Codeforces 834D The Bakery【dp+线段树维护+lazy】

    D. The Bakery time limit per test:2.5 seconds memory limit per test:256 megabytes input:standard inp ...

随机推荐

  1. org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'list' in 'c

     org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'list' in ' ...

  2. [转]关于ReentrantLock中线程读某个变量是否需要加锁

    我在使用ReentrantLock类对变量进行多线程累加时,调用了lock()和unlock()方法,但读取该变量时我未加锁,结果是能正确执行,代码如下: public class Main { pr ...

  3. 原 spring-boot工程中,jpa下hibernate的ddl-auto的各种属性

    jpa:  hibernate:    ddl-auto: create ddl-auto:create----每次运行该程序,没有表格会新建表格,表内有数据会清空 ddl-auto:create-d ...

  4. x=x+1, x += 1, x++ 效率分析

    x = x + 1 效率最低 具体如下: 1. 读取右x的地址 2. x + 1 3. 读取左x的地址 4. 将右值传给左边的x(编译器不认为左x和右x是同一个地址) x += 1 其次 1. 读取右 ...

  5. zhuan 常用图像数据集:标注、检索

      目录(?)[+]   1.搜狗实验室数据集: http://www.sogou.com/labs/dl/p.html 互联网图片库来自sogou图片搜索所索引的部分数据.其中收集了包括人物.动物. ...

  6. Linux第九周作业

    学习笔记 不同类型的进程有不同的调度需求,其中分为两类 第一类:I/O-bound(频繁进行I/O,花费长时间等待I/O操作的完成)CPU-bound(计算密集型,需要大量的CPU时间进行运算) 第二 ...

  7. Uboot USB模式(RK3288变砖头的解决办法)

    RK3288启动后有三种模式,可以分别进行操作. 第一种是normal也就是正常的启动模式.这个模式无法刷固件.一般板子通电就是这个模式 第二种是loader模式.就是刷固件模式.这个模式可以刷各种i ...

  8. docker图形化管理工具portainer

    本章主要介绍docker的web图形化管理工具.这里使用 portainer(类似与dockui不过dockerui只支持单节点) 镜像名称 portainer/portainer 一.启动porta ...

  9. node 慕课笔记

    global global.testVar2 = 200; 在别的文件中可以任意调用到 因为global是全局变量相当于js的window一样的

  10. Android开发 ---从互联网上下载文件,回调函数,图片压缩、倒转

     Android开发 ---从互联网上下载文件,回调函数,图片压缩.倒转 效果图: 描述: 当点击“下载网络图像”按钮时,系统会将图二中的照片在互联网上找到,并显示在图像框中 注意:这个例子并没有将图 ...