[矩阵乘法][线段树][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 }