LINK
K. Addition Robot
time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Adding two numbers several times is a time-consuming task, so you want to build a robot. The robot should have a string S=S1S2…SN of N characters on its memory that represents addition instructions. Each character of the string, Si, is either ‘A’ or ‘B’.
You want to be able to give Q commands to the robot, each command is either of the following types:
1 L R. The robot should toggle all the characters of Si where L≤i≤R. Toggling a character means changing it to ‘A’ if it was previously ‘B’, or changing it to ‘B’ if it was previously ‘A’.
2 L R A B. The robot should call f(L,R,A,B) and return two integers as defined in the following pseudocode:
function f(L, R, A, B):
FOR i from L to R
if S[i] = ‘A’
A = A + B
else
B = A + B
return (A, B)
You want to implement the robot’s expected behavior.
Input
Input begins with a line containing two integers: N Q (1≤N,Q≤100000) representing the number of characters in the robot’s memory and the number of commands, respectively. The next line contains a string S containing N characters (each either ‘A’ or ‘B’) representing the initial string in the robot’s memory. The next Q lines each contains a command of the following types.
1 L R (1≤L≤R≤N)
2 L R A B (1≤L≤R≤N; 0≤A,B≤109)
There is at least one command of the second type.
Output
For each command of the second type in the same order as input, output in a line two integers (separated by a single space), the value of A and B returned by f(L,R,A,B), respectively. As this output can be large, you need to modulo the output by 1000000007.
Example
inputCopy
5 3
ABAAA
2 1 5 1 1
1 3 5
2 2 5 0 1000000000
outputCopy
11 3
0 1000000000
CF 的时候完全没思路QAQ
第一份code是看了大佬的代码(%%%)照着思路打的
照着模拟一遍 get 到了一些点 下下面还有自己的一点idea(叙述过于冗长)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=1e9+7;
typedef long long ll;
int n,m;char s[N];
struct node{
ll m[2][2];
node(){
for(int i=0;i<2;i++) for(int j=0;j<2;j++) m[i][j]=0;
}
friend node operator*(const node &a,const node &b)
{//矩阵相乘
node c;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
{
c.m[i][j]+=a.m[i][k]*b.m[k][j]; c.m[i][j]%=mod;
}
return c;
}
void change(){//矩阵转置
swap(m[1][1],m[0][0]);swap(m[1][0],m[0][1]);
}
}t[N<<2],A,B;
int tag[N<<2];//懒标记
void build(int l,int r,int rt)
{
if(l==r)
{
if(s[l]=='A') t[rt]=A;
else t[rt]=B;
return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
t[rt]=t[rt<<1]*t[rt<<1|1];
}
void pushdown(int rt)
{
tag[rt]=0;
tag[rt<<1|1]^=1;
tag[rt<<1]^=1;
t[rt<<1].change();
t[rt<<1|1].change();
}
void update(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
tag[rt]^=1;
t[rt].change();
return ;
}
if(tag[rt]) pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid) update(L,R,l,mid,rt<<1);
if(R>mid) update(L,R,mid+1,r,rt<<1|1);
t[rt]=t[rt<<1]*t[rt<<1|1];
}
node query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return t[rt];
}
if(tag[rt]) pushdown(rt);
int mid=(l+r)>>1;
node ans;
ans.m[0][0]=ans.m[1][1]=1;
if(L<=mid) ans=(ans*query(L,R,l,mid,rt<<1));
if(R>mid) ans=(ans*query(L,R,mid+1,r,rt<<1|1));
return ans;
}
int main()
{
A.m[0][1]=A.m[0][0]=A.m[1][1]=1;//A=A+B
B.m[1][1]=B.m[1][0]=B.m[0][0]=1; //B=A+B
cin>>n>>m>>(s+1);
reverse(s+1,s+1+n);
build(1,n,1);int l, r;ll a,b;
while(m--)
{
int op;scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&l,&r);
update(n+1-r,n+1-l,1,n,1);//更新
}else
{
scanf("%d%d%lld%lld",&l,&r,&a,&b);
node ans=query(n+1-r,n+1-l,1,n,1);//询问
printf("%lld %lld\n",(ans.m[0][1]*b%mod+ans.m[0][0]*a%mod)%mod,(ans.m[1][0]*a%mod+ans.m[1][1]*b%mod)%mod);
}
}
}
->->仔细想想自己改了一下就是正常的矩阵相乘A * B=C 就应该是C中(X,Y)位置上的数值就应该是A中 X这一行的数乘以对应的B 中Y列上面的数之和 稍微改变一下,考虑矩阵C(X,Y)上的数是由 A X列的数乘以B Y行的数之和
二维矩阵(矩阵用来存系数啊
X Y----A
Z K----B
(X ,Z分别表示 此时 A B中a的系数,同理Y ,K 分别表示A B中b的系数
AA BB也就是代码里的A,B这里为了不弄混
AA矩阵://对应A =A+B
1 1
0 1
BB矩阵://B=A+B
1 0
1 1
考虑~对应的元素是A就把目前B累计的a,b,系数全部累加到A上,B不变
对应的是B就把A的a,b系数全部累加到B上 A不变
按以上的想法):对于A B序列从A到B 采用ans=pre(之前的矩阵也就是AA )*目前的元素矩阵(BB) =
AA *BB =
1 1
1 2
对于所得的矩阵也就是即为C C(0,0)=AA(0,0)*BB(0,0)+AA(1,0)*BB(0,1)
=1 * 1+0 * 1=1 也就是ans中A对应的a的系数 …
这时候就是上面矩阵AA BB 的作用 BB的第一行1 0 与前面pre中的a系数分别相乘,现在对于此时A的a系数只能接受来自上一个A本身的a而拒绝来自上一个B的a ,而第二行 1 1 表示此时的B的a(或b)可以接受来自之前A 的a(b)也可以接受来自之前B的a(b)
其余同理啊
~~感觉越讲越乱啊 明明超级简单的QAQ
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=1e9+7;
typedef long long ll;
int n,m;char s[N];
struct node{
ll m[2][2];
node(){
for(int i=0;i<2;i++) for(int j=0;j<2;j++) m[i][j]=0;
}
//和上一份code主要区别就是下面的opertor里面的a b交换位子,实现矩阵乘法的重置!!!
friend node operator*(const node &b,const node &a)
{//矩阵相乘
node c;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
{
c.m[i][j]+=a.m[i][k]*b.m[k][j]; c.m[i][j]%=mod;
}
return c;
}
void change(){//矩阵转置
swap(m[1][1],m[0][0]);swap(m[1][0],m[0][1]);
}
}t[N<<2],A,B;
int tag[N<<2];//懒标记
void build(int l,int r,int rt)
{
if(l==r)
{
if(s[l]=='A') t[rt]=A;
else t[rt]=B;
return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
t[rt]=t[rt<<1]*t[rt<<1|1];
}
void pushdown(int rt)
{
tag[rt]=0;
tag[rt<<1|1]^=1;
tag[rt<<1]^=1;
t[rt<<1].change();
t[rt<<1|1].change();
}
void update(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
tag[rt]^=1;
t[rt].change();
return ;
}
if(tag[rt]) pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid) update(L,R,l,mid,rt<<1);
if(R>mid) update(L,R,mid+1,r,rt<<1|1);
t[rt]=t[rt<<1]*t[rt<<1|1];
}
node query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return t[rt];
}
if(tag[rt]) pushdown(rt);
int mid=(l+r)>>1;
node ans;
ans.m[0][0]=ans.m[1][1]=1;
if(L<=mid) ans=(ans*query(L,R,l,mid,rt<<1));
if(R>mid) ans=(ans*query(L,R,mid+1,r,rt<<1|1));
return ans;
}
int main()
{
A.m[0][1]=A.m[0][0]=A.m[1][1]=1;//A=A+B
B.m[1][1]=B.m[1][0]=B.m[0][0]=1; //B=A+B
cin>>n>>m>>(s+1);
//reverse(s+1,s+1+n);
build(1,n,1);int l, r;ll a,b;
while(m--)
{
int op;scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&l,&r);
update(l,r,1,n,1);//更新
}else
{
scanf("%d%d%lld%lld",&l,&r,&a,&b);
node ans=query(l,r,1,n,1);//询问
printf("%lld %lld\n",(ans.m[0][1]*b%mod+ans.m[0][0]*a%mod)%mod,(ans.m[1][0]*a%mod+ans.m[1][1]*b%mod)%mod);
}
}
}