[矩阵乘法][线段树][dp] Hdu P6155 Subsequence Count

 

 

 题解

  • 首先我们考虑dp,设f[i][0/1]为做到si,以0或1结尾的方案数
  • f[i][0]=f[i-1][0]+f[i-1][1]+1,f[i][1]=f[i-1][1] (当si==0时)
  • f[i][1]=f[i-1][0]+f[i-1][1]+1,f[i][0]=f[i-1][0] (当si==1时)
  • 考虑将其变成类似矩阵乘法的东东
  • 然后搞不考虑区间反转的话就可以取得40分的好成绩
  • 可以用线段树来维护矩阵乘法,那么现在考虑区间取反操作怎么搞
  • 当一个区间内的01串翻转之后相当于区间的矩阵第一行变为第二行,第一列变为第二列

 

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #define ll long long 
 4 using namespace std;
 5 const ll N=1e5+10,mo=1e9+7;
 6 int T,n,q,tag[N*4];
 7 char s[N];
 8 struct matrix
 9 {
10     ll a[2][2];
11     void init(int d) 
12     { 
13         if  (d>0) a[0][0]=a[0][1]=a[1][1]=1,a[1][0]=0; else  a[0][0]=a[1][0]=a[1][1]=1,a[0][1]=0; 
14     }
15     void change() { swap(a[0][0],a[1][1]),swap(a[0][1],a[1][0]); }
16     matrix operator *(const matrix &b) const
17     {
18         matrix c;
19         for (int i=0;i<2;i++) for (int j=0;j<2;j++) 
20         {
21             c.a[i][j]=0;
22             for (int k=0;k<2;k++) c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j])%mo;
23         }
24         return c;
25     }
26 }mul[N*4],ans;
27 void pushdown(int d) { if (tag[d]) tag[d*2]^=1,tag[d*2+1]^=1,mul[d*2].change(),mul[d*2+1].change(),tag[d]=0; }
28 void build(int d,int l,int r)
29 {
30     tag[d]=0;
31     if (l==r) { mul[d].init(s[l]-'0'); return; }
32     int mid=l+r>>1;
33     build(d*2,l,mid),build(d*2+1,mid+1,r),mul[d]=mul[d*2]*mul[d*2+1];
34 }
35 void change(int d,int l,int r,int L,int R)
36 {
37     if (L<=l&&r<=R) { tag[d]^=1,mul[d].change(); return; }
38     pushdown(d); int mid=l+r>>1;
39     if (L<=mid) change(d*2,l,mid,L,R);
40     if (mid<R) change(d*2+1,mid+1,r,L,R);
41     mul[d]=mul[d*2]*mul[d*2+1];
42 }
43 matrix query(int d,int l,int r,int L,int R)
44 {
45     if (L<=l&&r<=R) return mul[d];
46     int mid=l+r>>1; matrix res; pushdown(d);
47     res.a[0][0]=res.a[1][1]=1,res.a[0][1]=res.a[1][0]=0;
48     if (L<=mid) res=res*query(d*2,l,mid,L,R);
49     if (mid<R) res=res*query(d*2+1,mid+1,r,L,R);
50     return res;
51 }
52 int main()
53 {
54     for (scanf("%d",&T);T;T--)
55     { 
56         scanf("%d%d%s",&n,&q,s+1),build(1,1,n);
57         for (int op,l,r;q;q--)
58         {
59             scanf("%d%d%d",&op,&l,&r);
60             if (op==2) ans=query(1,1,n,l,r),printf("%lld\n",(ans.a[0][0]+ans.a[0][1]+ans.a[1][0]+ans.a[1][1]-2ll+mo)%mo); else change(1,1,n,l,r);
61         } 
62     } 
63 }

 

posted @ 2019-08-16 15:44  BEYang_Z  阅读(331)  评论(0编辑  收藏  举报