[HDU6155]Subsequence Count(线段树+矩阵)
DP式很容易得到,发现是线性递推形式,于是可以矩阵加速。又由于是区间形式,所以用线段树维护。
https://www.cnblogs.com/Miracevin/p/9124511.html
关键在于证明区间操作中,可以直接在打标记的位置翻转矩阵两行两列。
上面网址用代数形式证了一遍,这里考虑从矩阵本身解释。
由线代内容可知,将一个矩阵作初等行变换,相当于将其左乘一个作了相应初等列变换的单位矩阵。同理将一个矩阵作初等列变换,相当于将其又乘一个作了相应初等行变换的单位矩阵。
这里,左乘的矩阵$T=\begin{bmatrix}0 & 1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1\end{bmatrix}$,右乘的矩阵$T'$同样也是这个。
我们发现,$T\times T'$就是单位矩阵,也就是说$T$的逆矩阵就是自己。
于是有,$T\times A\times T'\times T\times B\times T'=T\times A\times B\times T'$。
这就说明中间的所有矩乘操作都可以被省略,只留下首尾的$T$和$T'$。
这也就证明了,对区间矩阵积直接做变换是正确的。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define ls (x<<1) 5 #define rs (ls|1) 6 #define lson ls,L,mid 7 #define rson rs,mid+1,R 8 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 9 using namespace std; 10 11 const int N=100010,mod=1e9+7; 12 bool tag[N<<2]; 13 int n,Q,T,op,l,r; 14 15 struct Mat{ int a[3][3]; }v[N<<2]; 16 const Mat D[2]={(Mat){1,0,0,1,1,0,1,0,1},(Mat){1,1,0,0,1,0,0,1,1}}; 17 int calc(Mat a){ return (a.a[2][0]+a.a[2][1])%mod; } 18 19 Mat operator *(const Mat &a,const Mat &b){ 20 Mat c; memset(c.a,0,sizeof(c.a)); 21 rep(i,0,2) rep(j,0,2) rep(k,0,2) 22 c.a[i][k]=(c.a[i][k]+1ll*a.a[i][j]*b.a[j][k])%mod; 23 return c; 24 } 25 26 void put(int x){ 27 tag[x]^=1; 28 swap(v[x].a[0][0],v[x].a[1][0]); 29 swap(v[x].a[0][1],v[x].a[1][1]); 30 swap(v[x].a[0][2],v[x].a[1][2]); 31 swap(v[x].a[0][0],v[x].a[0][1]); 32 swap(v[x].a[1][0],v[x].a[1][1]); 33 swap(v[x].a[2][0],v[x].a[2][1]); 34 } 35 36 void push(int x){ if (tag[x]) put(ls),put(rs),tag[x]=0; } 37 38 void build(int x,int L,int R){ 39 tag[x]=0; 40 if (L==R){ char t; scanf(" %c",&t); v[x]=D[t-'0']; return; } 41 int mid=(L+R)>>1; build(lson); build(rson); v[x]=v[ls]*v[rs]; 42 } 43 44 void mdf(int x,int L,int R,int l,int r){ 45 if (L==l && r==R){ put(x); return; } 46 int mid=(L+R)>>1; push(x); 47 if (r<=mid) mdf(lson,l,r); 48 else if (l>mid) mdf(rson,l,r); 49 else mdf(lson,l,mid),mdf(rson,mid+1,r); 50 v[x]=v[ls]*v[rs]; 51 } 52 53 Mat que(int x,int L,int R,int l,int r){ 54 if (L==l && r==R) return v[x]; 55 int mid=(L+R)>>1; push(x); 56 if (r<=mid) return que(lson,l,r); 57 else if (l>mid) return que(rson,l,r); 58 else return que(lson,l,mid)*que(rson,mid+1,r); 59 } 60 61 int main(){ 62 freopen("hdu6155.in","r",stdin); 63 freopen("hdu6155.out","w",stdout); 64 for (scanf("%d",&T); T--; ){ 65 scanf("%d%d",&n,&Q); build(1,1,n); 66 while (Q--){ 67 scanf("%d%d%d",&op,&l,&r); 68 if (op==1) mdf(1,1,n,l,r); else printf("%d\n",calc(que(1,1,n,l,r))); 69 } 70 } 71 return 0; 72 }