【绝世好题】HDU 6155 Subsequence Count(dp+线段树+维护矩阵乘)

题意:

给出一个长度为n的01串s,两种操作:
1.反转区间[l,r],即把0变成1,把1变成0
2.询问区间[l,r]中不同的子序列个数

思路:

#include<bits/stdc++.h>
using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
typedef long long ll;
typedef pair<int,int>pii;
const ll INF=0x3f3f3f3f;
const ll mod=1e9+7;
const int maxn=1e5+6;
int T,n,q,lazy[maxn<<2];
char s[maxn];
struct node{
	ll a[3][3];
	node operator * (const node& x){
		node t;
		memset(t.a,0,sizeof(t.a));
		for(int i=0;i<=2;i++)
		    for(int j=0;j<=2;j++)
		       for(int k=0;k<=2;k++)
		           t.a[i][j]=(t.a[i][j]+a[i][k]*x.a[k][j]%mod)%mod;
		return t;
	}
}e[maxn<<2];
node st[2]={{1,0,0,1,1,0,1,0,1},{1,1,0,0,1,0,0,1,1}};
void pushup(int rt){
	e[rt]=e[rt<<1]*e[rt<<1|1];
}
void build(int rt,int l,int r){
	lazy[rt]=0;
	if(l==r){
		e[rt]=st[s[l]-'0'];
		return;
	}
	int mid=(l+r)>>1;
	build(lson);
	build(rson);
	pushup(rt);
}
void upnow(int rt){
	swap(e[rt].a[0][0],e[rt].a[1][1]);
	swap(e[rt].a[1][0],e[rt].a[0][1]);
	swap(e[rt].a[2][0],e[rt].a[2][1]);
	swap(e[rt].a[0][2],e[rt].a[1][2]);
}
void pushdown(int rt){
	if(lazy[rt]){
		upnow(rt<<1);
		upnow(rt<<1|1);
		lazy[rt<<1]^=1;
		lazy[rt<<1|1]^=1;
		lazy[rt]=0;
	}
}
void update(int rt,int l,int r,int x,int y){
	if(x<=l&&r<=y){
		upnow(rt);
		lazy[rt]^=1;
		return;
	}
	int mid=(l+r)>>1;
	pushdown(rt);
	if(x<=mid)update(lson,x,y);
	if(y>mid)update(rson,x,y);
	pushup(rt);
}
node query(int rt,int l,int r,int x,int y){
	if(x<=l&&r<=y)return e[rt];
	int mid=(l+r)>>1;
	pushdown(rt);
	node res={1,0,0,0,1,0,0,0,1};
	if(x<=mid)res=res*query(lson,x,y);
	if(y>mid)res=res*query(rson,x,y);
	return res;
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%s",&n,&q,s+1);
		build(1,1,n);
		while(q--){
			int op,x,y;
			scanf("%d%d%d",&op,&x,&y);
			if(op==1){
				update(1,1,n,x,y);
			}
			else {
				node ans=query(1,1,n,x,y);
				node h={0,0,1,0,0,0,0,0,0};
				h=h*ans;
				printf("%lld\n",(h.a[0][0]+h.a[0][1])%mod);
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值