码迷,mamicode.com
首页 > 其他好文 > 详细

[HDU6155]Subsequence Count(线段树+矩阵)

时间:2019-01-19 20:08:54      阅读:266      评论:0      收藏:0      [点我收藏+]

标签:out   ==   维护   efi   stdin   线性   标记   hdu   log   

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 }

 

[HDU6155]Subsequence Count(线段树+矩阵)

标签:out   ==   维护   efi   stdin   线性   标记   hdu   log   

原文地址:https://www.cnblogs.com/HocRiser/p/10292914.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!