HDU 6155 Subsequence Count [線段樹維護矩陣]
阿新 • • 發佈:2018-12-24
題意:給你長度為n的01串,m個操作,每次操作有兩種
①將區間[L,R]取反(0變1,1變0)
②詢問區間[L,R]的所有不同子序列的和
題解:首先我們考慮對於一個01串,我們如何知道它的不同的子序列個數。發現我們可以通過dp來求得
①對於新加入的1來說,dp轉移方程為dp[i][1]=dp[i-1][0]+dp[i-1][1]+1;dp[i][0]=dp[i-1][0]。
②對於新加入的0來說,dp轉移方程為dp[i][0]=dp[i-1][0]+dp[i-1][1]+1;dp[i][1]=dp[i-1][1]。
從上面的dp轉移方程式我們可以得到一個結論:我們可以通過判斷新加入字元是0還是1,通過矩陣來表達結果。
例如:
①對於新加入1,我們可以設計這樣的矩陣操作。
②對於新加入0,我們可以設計這樣的矩陣操作。
當我們需要翻轉更新的時候,我們只需要先將矩陣的第一列和第二列交換,再將矩陣的第一行和第一列交換就能得到答案。翻轉後打上標記即可。
AC程式碼:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 100005 #define mod 1000000007 using namespace std; typedef long long ll; struct Matrix { ll mat[3][3]; Matrix(){} Matrix(ll a[3][3]) { for(ll i=0;i<3;i++) for(ll j=0;j<3;j++) mat[i][j]=a[i][j]; } }tree[N*4],lin,yi,c; ll rev[N*4]; char a[100005]; ll LIN[3][3]={ {1,0,0}, {1,1,0}, {1,0,1} }; ll YI[3][3]={ {1,1,0}, {0,1,0}, {0,1,1} }; Matrix multi(Matrix a,Matrix b) { memset(c.mat,0,sizeof(c.mat)); for(ll i=0;i<3;i++) for(ll j=0;j<3;j++) for(ll k=0;k<3;k++) c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod; return c; } void build(ll L,ll R,ll root) { if(L==R) { if(a[L]=='0')tree[root]=lin; else tree[root]=yi; return ; } ll mid=L+R>>1; build(L,mid,root<<1); build(mid+1,R,root<<1|1); tree[root]=multi(tree[root<<1],tree[root<<1|1]); } void change(Matrix &a) { for(ll i=0;i<3;i++) swap(a.mat[i][0],a.mat[i][1]); for(ll i=0;i<3;i++) swap(a.mat[0][i],a.mat[1][i]); } void pushdown(ll root) { change(tree[root<<1]); change(tree[root<<1|1]); rev[root<<1]^=1; rev[root<<1|1]^=1; rev[root]=0; } void update(ll l,ll r,ll L,ll R,ll root) { if(l<=L&&R<=r) { rev[root]^=1; change(tree[root]); return; } if(rev[root])pushdown(root); ll mid=L+R>>1; if(r<=mid)update(l,r,L,mid,root<<1); else if(l>mid)update(l,r,mid+1,R,root<<1|1); else { update(l,mid,L,mid,root<<1); update(mid+1,r,mid+1,R,root<<1|1); } tree[root]=multi(tree[root<<1],tree[root<<1|1]); } Matrix query(ll l,ll r,ll L,ll R,ll root) { if(l<=L&&R<=r) return tree[root]; if(rev[root])pushdown(root); ll mid=L+R>>1; if(r<=mid)return query(l,r,L,mid,root<<1); else if(l>mid)return query(l,r,mid+1,R,root<<1|1); else return multi(query(l,mid,L,mid,root<<1),query(mid+1,r,mid+1,R,root<<1|1)); tree[root]=multi(tree[root<<1],tree[root<<1|1]); } int main() { ll T; scanf("%lld",&T); lin=Matrix(LIN); yi=Matrix(YI); while(T--) { memset(tree,0,sizeof(tree)); memset(rev,0,sizeof(rev)); ll n,m; scanf("%lld%lld",&n,&m); scanf("%s",a+1); build(1,n,1); while(m--) { ll op,l,r; scanf("%lld%lld%lld",&op,&l,&r); if(op==1)update(l,r,1,n,1); else { c=query(l,r,1,n,1); printf("%lld\n",(c.mat[2][0]+c.mat[2][1])%mod); } } } }