CodeForces - 1252K Addition Robot(线段树维护矩阵)

题目链接:点击查看

题目大意:给出一个只由 A 和 B 组成的字符串 s ,需要完成 m 次操作,每次操作分为两种类型:

  1. 1 l r :将 [ l , r ] 内的字符串 A 变成 B,B 变成 A
  2. 2 l r a b:从左到右扫一遍字符串 s 的 [ l , r ] ,并求出最后的 a 和 b
    1. 如果 s[ i ] == ' B ' : b = a + b
    2. 如果 s[ i ] == ' A ' : a = a + b

题目分析:维护一段连续的 a 和 b 的变化,通过观察后不难发现其实可以用矩阵去维护:

这样操作二就得以维护了,但操作一该如何维护呢,如果只是观察单纯的一个 A 和 B 的转移矩阵,可以发现是经过上下翻转然后再经过左右翻转得到的,利用矩阵乘法多观察一下,当 n 大于一时,执行操作一后,同样也是需要将矩阵进行上下翻转然后左右翻转再得到的,证明的话我也不会,毕竟比赛的时候也不会考察证明嘛

所以对于操作一,写一个 reverse 函数执行上述操作即可

区间查询的话,可以用线段树维护矩阵,这样可以实现区间更新以及区间查询

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;
 
const int N=1e5+100;

const int mod=1e9+7;

char s[N];

struct Ma
{
	LL a[2][2];
	Ma operator*(const Ma& t)
	{
		Ma ans;
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
			{
				ans.a[i][j]=0;
				for(int k=0;k<2;k++)
					ans.a[i][j]=(ans.a[i][j]+a[i][k]*t.a[k][j])%mod;
			}
		return ans;
	}
}one;

struct Node
{
	int l,r;
	int rev;
	Ma maze;
}tree[N<<2];

void pushup(int k)
{
	tree[k].maze=tree[k<<1].maze*tree[k<<1|1].maze;
}

void reverse(int k)
{
	swap(tree[k].maze.a[0][0],tree[k].maze.a[0][1]);
	swap(tree[k].maze.a[1][0],tree[k].maze.a[1][1]);
	swap(tree[k].maze.a[0][0],tree[k].maze.a[1][0]);
	swap(tree[k].maze.a[0][1],tree[k].maze.a[1][1]);
}

void pushdown(int k)
{
	if(tree[k].rev)
	{
		tree[k].rev=0;
		tree[k<<1].rev^=1;
		tree[k<<1|1].rev^=1;
		reverse(k<<1);
		reverse(k<<1|1);
	}
}

void build(int k,int l,int r)
{
	tree[k].l=l;
	tree[k].r=r;
	tree[k].rev=0;
	if(l==r)
	{
		if(s[l]=='A')
		{
			tree[k].maze.a[0][0]=1;
			tree[k].maze.a[0][1]=0;
			tree[k].maze.a[1][0]=1;
			tree[k].maze.a[1][1]=1;
		}
		else
		{
			tree[k].maze.a[0][0]=1;
			tree[k].maze.a[0][1]=1;
			tree[k].maze.a[1][0]=0;
			tree[k].maze.a[1][1]=1;
		}
		return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}

void update(int k,int l,int r)
{
	if(tree[k].r<l||tree[k].l>r)
		return;
	if(tree[k].l>=l&&tree[k].r<=r)
	{
		reverse(k);
		tree[k].rev^=1;
		return;
	}
	pushdown(k);
	update(k<<1,l,r);
	update(k<<1|1,l,r);
	pushup(k);
}

Ma query(int k,int l,int r)
{
	if(tree[k].r<l||tree[k].l>r)
		return one;
	if(tree[k].l>=l&&tree[k].r<=r)
		return tree[k].maze;
	pushdown(k);
	return query(k<<1,l,r)*query(k<<1|1,l,r);
}

void init()
{
	one.a[0][0]=1;
	one.a[0][1]=0;
	one.a[1][0]=0;
	one.a[1][1]=1;
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	init();
	int n,m;
	scanf("%d%d",&n,&m);
	scanf("%s",s+1);
	build(1,1,n);
	while(m--)
	{
		int op;
		scanf("%d",&op);
		if(op==1)
		{
			int l,r;
			scanf("%d%d",&l,&r);
			update(1,l,r);
		}
		else
		{
			int l,r,a,b;
			scanf("%d%d%d%d",&l,&r,&a,&b);
			Ma ans2=query(1,l,r);
			Ma ans1;
			ans1.a[0][0]=a;
			ans1.a[0][1]=b;
			ans1.a[1][0]=0;
			ans1.a[1][1]=0;
			Ma ans=ans1*ans2;
			printf("%lld %lld\n",ans.a[0][0],ans.a[0][1]);
		}
	}






























   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/108310296
今日推荐