题目大意:
给定一个01序列,支持以下两种操作:
1.区间反转;
2.区间求不同的子序列数量。
思路:
首先我们考虑区间反转,这是一个经典的线段树操作。
接下来考虑求不同的子序列数量,在已知当前区间的情况下,我们有如下$O(n)$的动态规划:|
$f_{i,0}=f_{i-1,0}+f_{i-1,1}+1,f_{i,1}=f_{i-1,1}//第i位为0$
$f_{i,1}=f_{i-1,0}+f_{i-1,1}+1,f_{i,0}=f_{i-1,0}//第i位为1$
这样的动态规划显然无法直接用线段树维护,而如果不能直接用线段树维护,上面维护的区间反转也就失去了意义。
为了使用线段树维护这种动态规划,我们需要用矩阵表示这种递推关系。
$\left(\begin{array}{}f_{i+1,0}\\f_{i+1,1}\\1\end{array}\right)=\left(\begin{array}{}f_{i-1,0}\\f_{i-1,1}\\1\end{array}\right)\times\left(\begin{array}{}1&0&0\\1&1&0\\1&0&1\end{array}\right)$
$\left(\begin{array}{}f_{i+1,0}\\f_{i+1,1}\\1\end{array}\right)=\left(\begin{array}{}f_{i-1,0}\\f_{i-1,1}\\1\end{array}\right)\times\left(\begin{array}{}1&1&0\\0&1&0\\0&1&1\end{array}\right)$
这样我们就可以保存每个区间的乘积,询问时直接相乘即可。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 inline int getint() { 5 char ch; 6 while(!isdigit(ch=getchar())); 7 int x=ch^‘0‘; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 9 return x; 10 } 11 inline int getdigit() { 12 char ch; 13 while(!isdigit(ch=getchar())); 14 return ch^‘0‘; 15 } 16 const int N=100001,mod=1e9+7; 17 template<int SIZE> 18 struct Matrix { 19 int val[SIZE][SIZE]; 20 Matrix operator * (const Matrix &another) const { 21 Matrix ret; 22 for(int i=0;i<SIZE;i++) { 23 for(int j=0;j<SIZE;j++) { 24 ret.val[i][j]=0; 25 for(int k=0;k<SIZE;k++) { 26 ret.val[i][j]+=(long long)val[i][k]*another.val[k][j]%mod; 27 ret.val[i][j]%=mod; 28 } 29 } 30 } 31 return ret; 32 } 33 void operator *= (const Matrix &another) { 34 *this=*this*another; 35 } 36 void flip() { 37 std::swap(val[0][0],val[1][1]); 38 std::swap(val[0][1],val[1][0]); 39 std::swap(val[0][2],val[1][2]); 40 std::swap(val[2][0],val[2][1]); 41 } 42 int calc() { 43 return (val[2][0]+val[2][1])%mod; 44 } 45 }; 46 const Matrix<3> m[2]={ 47 {1,0,0, 48 1,1,0, 49 1,0,1}, 50 {1,1,0, 51 0,1,0, 52 0,1,1} 53 }; 54 const Matrix<3> E={ 55 1,0,0, 56 0,1,0, 57 0,0,1 58 }; 59 class SegmentTree { 60 private: 61 #define _left <<1 62 #define _right <<1|1 63 Matrix<3> val[N<<2]; 64 bool tag[N<<2]; 65 void push_up(const int p) { 66 val[p]=val[p _left]*val[p _right]; 67 } 68 void push_down(const int p) { 69 if(!tag[p]) return; 70 val[p _left].flip(); 71 val[p _right].flip(); 72 tag[p _left]^=true; 73 tag[p _right]^=true; 74 tag[p]=false; 75 } 76 public: 77 void build(const int p,const int b,const int e) { 78 tag[p]=false; 79 if(b==e) { 80 val[p]=m[getdigit()]; 81 return; 82 } 83 int mid=(b+e)>>1; 84 build(p _left,b,mid); 85 build(p _right,mid+1,e); 86 push_up(p); 87 } 88 void modify(const int p,const int b,const int e,const int l,const int r) { 89 if(b==l&&e==r) { 90 val[p].flip(); 91 tag[p]^=true; 92 return; 93 } 94 push_down(p); 95 int mid=(b+e)>>1; 96 if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r)); 97 if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r); 98 push_up(p); 99 } 100 Matrix<3> query(const int p,const int b,const int e,const int l,const int r) { 101 if(b==l&&e==r) { 102 return val[p]; 103 } 104 push_down(p); 105 int mid=(b+e)>>1; 106 Matrix<3> ret=E; 107 if(l<=mid) ret*=query(p _left,b,mid,l,std::min(mid,r)); 108 if(r>mid) ret*=query(p _right,mid+1,e,std::max(mid+1,l),r); 109 return ret; 110 } 111 }; 112 SegmentTree t; 113 int main() { 114 for(int T=getint();T;T--) { 115 int n=getint(),q=getint(); 116 t.build(1,1,n); 117 while(q--) { 118 int op=getint(),l=getint(),r=getint(); 119 switch(op) { 120 case 1: { 121 t.modify(1,1,n,l,r); 122 break; 123 } 124 case 2: { 125 printf("%d\n",t.query(1,1,n,l,r).calc()); 126 break; 127 } 128 } 129 } 130 } 131 return 0; 132 }