题目链接:点击查看
题目大意:给出一个只由 A 和 B 组成的字符串 s ,需要完成 m 次操作,每次操作分为两种类型:
- 1 l r :将 [ l , r ] 内的字符串 A 变成 B,B 变成 A
- 2 l r a b:从左到右扫一遍字符串 s 的 [ l , r ] ,并求出最后的 a 和 b
- 如果 s[ i ] == ' B ' : b = a + b
- 如果 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;
}