HDU 6155 Subsequence Count [线段树维护矩阵]

来源:互联网 发布:parallels 没有网络 编辑:程序博客网 时间:2024/05/24 05:36

题意:给你长度为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 1000000007using 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);}}}}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 八字没有正财怎么办 八字无根怎么办啊 开车撞死一条狗怎么办 小麦收割机滚筒轴老折怎么办 圆珠笔画白墙上怎么办 白墙上圆珠笔怎么办洗 按扣皮箱扣不上怎么办 拉链一边掉了怎么办 拉链一半掉了怎么办 去北戴河怎么办安检证 电脑空格键打字失灵怎么办 国外玩游戏延迟怎么办 韩服lol要求输韩文怎么办 智齿碰到牙神经怎么办 合影中有人去世怎么办 在家中遇到蛇怎么办 去澳门手机充电怎么办 商标撕下来胶怎么办 商标被提出异议怎么办 商标被别人用怎么办 商标申请不下来怎么办 注册商标有近似商标怎么办 电话话打不通怎么办 公司卖了商标怎么办 商标撕不下来怎么办 商标撕不下来时怎么办 商标还没下来怎么办 商标揭不下来怎么办 手机程序出现异常怎么办 公众号企业名称是*怎么办 家人生命受到威胁怎么办 海淘看不懂英文怎么办 对英语不感兴趣怎么办 装修无合同起诉怎么办 上海离职后档案怎么办 公司注销了银行帐户怎么办 360借条注销了怎么办 注销营业执照公章丢失怎么办 工厂招聘信息有假怎么办 个体餐饮怎么办核名 见父母后接下来怎么办