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


    DP式很容易得到,发现是线性递推形式,于是可以矩阵加速。又由于是区间形式,所以用线段树维护。

    https://www.cnblogs.com/Miracevin/p/9124511.html

    关键在于证明区间操作中,可以直接在打标记的位置翻转矩阵两行两列。

    上面网址用代数形式证了一遍,这里考虑从矩阵本身解释。

    由线代内容可知,将一个矩阵作初等行变换,相当于将其左乘一个作了相应初等列变换的单位矩阵。同理将一个矩阵作初等列变换,相当于将其又乘一个作了相应初等行变换的单位矩阵。

    这里,左乘的矩阵$T=egin{bmatrix}0 & 1 & 0 \ 1 & 0 & 0 \ 0 & 0 & 1end{bmatrix}$,右乘的矩阵$T'$同样也是这个。

    我们发现,$T imes T'$就是单位矩阵,也就是说$T$的逆矩阵就是自己。

    于是有,$T imes A imes T' imes T imes B imes T'=T imes A imes B imes 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
    ",calc(que(1,1,n,l,r)));
    69         }
    70     }
    71     return 0;
    72 }
  • 相关阅读:
    Golang 读写文件的操作
    初始 Elasticsearch
    数据存储单位的换算(bytes、KB MB GB TB PB EB ZB YB DB NB)
    Go 语言类型元信息的通用结构 _type
    空接口
    HashMap和Hashtable的区别
    谈谈final, finally, finalize的区别
    理解AOP
    Struts2 OGNL概述
    Struts2原理
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10292914.html
Copyright © 2020-2023  润新知