您的位置:首页 > 产品设计 > UI/UE

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

2017-08-21 13:13 459 查看
题意:给你长度为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;
retur
4000
n ;
}
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);
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: