Description
给出一个长度为n的
1.反转区间
2.询问区间[l,r]中不同的子序列个数
Input
第一行输入一整数T表示用例组数,之后输入两个整数
Output
对于每个2操作,输出不同子序列个数,结果模
Sample Input
2
4 4
1010
2 1 4
2 2 4
1 2 3
2 1 4
4 4
0000
1 1 2
1 2 3
1 3 4
2 1 4
Sample Output
11
6
8
10
Solution
先不考虑反转操作,对于串s1s2...sn,以dp[i][0/1]表示以第i位结尾的不同的子序列个数
如果
如果si=1,同理可得dp[i][0]=dp[i−1][0],dp[i][1]=dp[i−1][0]+dp[i−1][1]+1
令A=⎡⎣⎢111010001⎤⎦⎥,B=⎡⎣⎢100111001⎤⎦⎥
则如果si=0,则有(dp[i][0] dp[i][1] 1)=(dp[i−1][0] dp[i−1][1] 1)⋅A
如果si=1,则有(dp[i][0] dp[i][1] 1)=(dp[i−1][0] dp[i−1][1] 1)⋅B
而注意到A和
现在考虑反转操作,对于区间[l,r],每个位置对应一个转移矩阵(A/B),这些转移矩阵的乘积即为这个区间的转移矩阵,令这些转移矩阵为Cl,...,Cr,反转后转移矩阵为Dl,...,Dr,则有Di=PCiP,进而DlDl+1...Dr=PClCl+1...CrP,即反转后的区间转移矩阵即为反转前区间转移矩阵交换前两行和前两列,用线段树维护区间转移矩阵的乘积即可,每次修改不需要把该区间转移矩阵重新乘一遍,只需将之前的转移矩阵交换前两行前两列即可,这里一个小优化是转移矩阵前两行最后一个数字均为0,不需要交换,这样只需进行
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 100005
#define mod 1000000007
#define ls (t<<1)
#define rs ((t<<1)|1)
typedef int Mat[3][3];
int T,n,q;
char s[maxn];
Mat m[maxn<<2],A[2]={{1,0,0,1,1,0,1,0,1},{1,1,0,0,1,0,0,1,1}},ans;
bool Lazy[maxn<<2];
void mul(Mat a,Mat b,Mat &c)
{
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
{
ll temp=0;
for(int k=0;k<3;k++)temp+=(ll)a[i][k]*b[k][j];
c[i][j]=temp%mod;
}
}
void deal(int t)
{
swap(m[t][0][0],m[t][0][1]);
swap(m[t][1][0],m[t][1][1]);
swap(m[t][2][0],m[t][2][1]);
swap(m[t][0][0],m[t][1][0]);
swap(m[t][0][1],m[t][1][1]);
}
void build(int l,int r,int t)
{
Lazy[t]=0;
if(l==r)
{
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
m[t][i][j]=A[s[l]-'0'][i][j];
return ;
}
int mid=(l+r)/2;
build(l,mid,ls);build(mid+1,r,rs);
mul(m[ls],m[rs],m[t]);
}
void push_down(int t)
{
if(Lazy[t])
{
Lazy[t]=0;
Lazy[ls]^=1,Lazy[rs]^=1;
deal(ls),deal(rs);
}
}
void update(int L,int R,int l,int r,int t)
{
if(L<=l&&r<=R)
{
Lazy[t]^=1;
deal(t);
return ;
}
push_down(t);
int mid=(l+r)/2;
if(L<=mid)update(L,R,l,mid,ls);
if(R>mid)update(L,R,mid+1,r,rs);
mul(m[ls],m[rs],m[t]);
}
void query(int L,int R,int l,int r,int t)
{
if(L<=l&&r<=R)
{
Mat temp;
mul(ans,m[t],temp);
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
ans[i][j]=temp[i][j];
return ;
}
push_down(t);
int mid=(l+r)/2;
if(L<=mid)query(L,R,l,mid,ls);
if(R>mid)query(L,R,mid+1,r,rs);
mul(m[ls],m[rs],m[t]);
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&q);
scanf("%s",s+1);
build(1,n,1);
while(q--)
{
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==1)update(l,r,1,n,1);
else
{
memset(ans,0,sizeof(ans));
ans[0][0]=ans[1][1]=ans[2][2]=1;
query(l,r,1,n,1);
printf("%d\n",(ans[2][0]+ans[2][1])%mod);
}
}
}
return 0;
}