题意:找子区间的子序列,多种操作,多种查询,操作为翻转区间01串;
思路:线段树维护区间矩阵;
首先看递推方程:当是s[i]=0时dp[i][0]=dp[i-1][0]+dp[i-1][1]+1,dp[i][1]=dp[i-1][1];为一的时候同理,再次发现我们需要一个三维矩阵来更新递推式,那我们来变换一下式子,dp[i][0]+1=dp[i-1][0]+1+dp[i-1][1]+1,dp[i][1]+1=dp[i-1][1]+1;那我们发现三维矩阵变成二维的了,则复杂度便从3^3降为2^2(矩阵乘积时候),接下来又发现,s[i]=0,s[i]=1的时候递推矩阵刚好是第一行变为第二行,第一列变为第二列,如此,当一个区间内的01串翻转之后相当于区间的矩阵第一行变为第二行,第一列变为第二列,对此可能不好想到,不过可以用矩阵初等变换推出,因此,每次区间翻转只需要转换一下矩阵即可,代码算是比较优化的:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define L l , m , u << 1 #define R m + 1 , r , u << 1 | 1 typedef long long LL; const int maxn=1e5+100; const LL mod=1e9+7; char s[maxn]; struct Matrix { LL v[2][2]; void init(int g) { if(g)v[0][0]=v[0][1]=v[1][1]=1,v[1][0]=0; else v[0][0]=v[1][0]=v[1][1]=1,v[0][1]=0; } Matrix operator *(const Matrix &m)const { Matrix c; for(int i=0;i<2;i++) for(int j=0;j<2;j++) { c.v[i][j]=0; for(int k=0;k<2;k++) c.v[i][j]=(c.v[i][j]+v[i][k]*m.v[k][j])%mod; } return c; } void rev() { swap(v[0][0],v[1][1]); swap(v[0][1],v[1][0]); } }; bool lz[maxn<<2]; Matrix mul[maxn<<2]; void PushUp(int u)//把当前结点的信息更新到父结点 { mul[u] = mul[u<<1]*mul[u<<1|1]; } void PushDown(int u)//把当前结点的信息更新给儿子结点 { if (lz[u]) { lz[u<<1] ^= 1; lz[u<<1|1] ^= 1; mul[u<<1].rev(); mul[u<<1|1].rev(); lz[u] = 0; } } void build(int l,int r,int u) { lz[u] = 0; if (l == r) { mul[u].init(s[l]-'0'); return ; } int m = (l + r) >> 1; build(L); build(R); PushUp(u); } void update(int l1,int r1,int l,int r,int u) { if (l1 <= l && r <= r1) { lz[u] ^= 1; mul[u].rev(); return ; } PushDown(u); int m = (l + r) >> 1; if (l1 <= m) update(l1 , r1 , L); if (m < r1) update(l1 , r1 , R); PushUp(u); } Matrix query(int l1,int r1,int l,int r,int u) { if (l1 <= l && r <= r1) { return mul[u]; } PushDown(u); int m = (l + r) >> 1; Matrix res; res.v[0][0]=res.v[1][1]=1; res.v[0][1]=res.v[1][0]=0; if (l1<= m) res =res * query(l1 , r1 , L); if (m < r1) res = res * query(l1 , r1 , R); return res; } int main() { //freopen("input.txt","r",stdin); int T;scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); scanf("%s",s+1); build(1,n,1); while(m--) { int k,l,r; scanf("%d%d%d",&k,&l,&r); if(k==1)update(l,r,1,n,1); else { Matrix t= query(l,r,1,n,1); LL ans=t.v[0][0]+t.v[0][1]+t.v[1][0]+t.v[1][1]-2; printf("%lld ",(ans+mod)%mod); } } } return 0; }