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

题目:

Adding two numbers several times is a time-consuming task, so you want to build a robot. The robot should have a string S=S1S2SNS=S1S2…SN of NN characters on its memory that represents addition instructions. Each character of the string, SiSi, is either 'A' or 'B'.

You want to be able to give QQ commands to the robot, each command is either of the following types:

  • LRR. The robot should toggle all the characters of SiSi where LiRL≤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'.
  • LRABB. The robot should call f(L,R,A,B)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: NQQ (1N,Q1000001≤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 SS containing NN characters (each either 'A' or 'B') representing the initial string in the robot's memory. The next QQ lines each contains a command of the following types.

  • LRR (1LRN1≤L≤R≤N)
  • LRABB (1LRN1≤L≤R≤N; 0A,B1090≤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 AA and BB returned by f(L,R,A,B)f(L,R,A,B), respectively. As this output can be large, you need to modulo the output by 10000000071000000007.

Example

Input
5 3
ABAAA
2 1 5 1 1
1 3 5
2 2 5 0 1000000000
Output
11 3
0 1000000000

Note

Explanation for the sample input/output #1

For the first command, calling f(L,R,A,B)f(L,R,A,B) causes the following:

  • Initially, A=1A=1 and B=1B=1.
  • At the end of i=1i=1, A=2A=2 and B=1B=1.
  • At the end of i=2i=2, A=2A=2 and B=3B=3.
  • At the end of i=3i=3, A=5A=5 and B=3B=3.
  • At the end of i=4i=4, A=8A=8 and B=3B=3.
  • At the end of i=5i=5, A=11A=11 and B=3B=3.

Therefore, f(L,R,A,B)f(L,R,A,B) will return (11,3)(11,3).

 

For the second command, string SS will be updated to "ABBBB".

For the third command, the value of AA will always be 00 and the value of BB will always be 10000000001000000000. Therefore, f(L,R,A,B)f(L,R,A,B) will return (0,1000000000)(0,1000000000).

题意:

  给你长度为n的字符串,只有A和B两种字符,有两种操作。

  1.给定区间[l,r],把区间内的A变成B,B变成A

  2.给定区间[l,r],还有2个数x,y,区间从左到右,如果s[i] = 'A' 则x = x + y,如果s[i] = 'B'则y = x + y。问最后x和y各是多少(mod1e9+7)。

 

思路:

  首先观察x=x+y,y=x+y这两个式子

  如果字符是A,则x = x + y,y = 0 * x + y

  如果字符是B,则x = x + 0 * y, y = x + y

  看出有个系数关系,可用矩阵表示

  

  即用矩阵乘法计算x和y的最终结果,矩阵的乘积可以用线段树维护。

  关于第二个操作,即翻转字符

  假设前者的结果是 x = ax + by  y = cx + dy

  A的意思是把x+y的值赋给x,B的意思是把x+y的值赋给y

  翻转之后A和B的位置刚好变换,那么最后肯定是x和y的系数互换。

  当然也可以把后者的y看成x,x看成y(换元法),遵循这个思路把前者的x和y替换掉,得到 y = ay +bx    x=cy+dx

  (另一个数同理)

 

 

  对比一下结果,容易发现翻转一个序列 = 区间矩阵乘积内的数交叉互换

  

 

   当然也可以写出AA和BB的结果,对比一下找找规律。

 

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 7;
const int mod = 1e9 + 7;
struct node {
    ll mx[2][2];
    node(ll a=0,ll b=0,ll c=0,ll d=0) {
        mx[0][0] = a;
        mx[0][1] = b;
        mx[1][0] = c;
        mx[1][1] = d;
    }
    node operator * (const node b) const {
        node c = node(0,0,0,0);
        for (int i=0; i<2; ++i)
            for (int j=0; j<2; ++j)
                for (int k=0; k<2; ++k) 
                    c.mx[i][j] = (c.mx[i][j] + mx[i][k] * b.mx[k][j] % mod) % mod;
        return c;
    }
    void nswap() {
        swap(mx[0][0],mx[1][1]);
        swap(mx[0][1],mx[1][0]);
    }
}tr[maxn<<3];

int n,q,x,l,r,lz[maxn<<3];
ll a,b;
char s[maxn];
void pushdown(int rt) {
    if(lz[rt]) {
        tr[rt].nswap();
        lz[rt<<1] ^= 1;
        lz[rt<<1|1] ^= 1;
        lz[rt] = 0;
    }
}
void build(int l,int r,int rt) {
    if(l == r) {
        if(s[l] == 'A') tr[rt] = node(1,0,1,1);
        else tr[rt] = node(1,1,0,1);
        return;
    }
    int mid = l + r >> 1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    tr[rt] = tr[rt<<1] * tr[rt<<1|1];
}
void update(int l,int r,int rt,int L,int R) {
    pushdown(rt);
    if(L<=l && r<=R) {
        lz[rt] ^= 1;
        return;
    }
    int mid = l + r >> 1;
    if(L<=mid) update(l,mid,rt<<1,L,R);
    if(mid<R) update(mid+1,r,rt<<1|1,L,R);
    if(l!=r) {
        pushdown(rt<<1);
        pushdown(rt<<1|1);
        tr[rt] = tr[rt<<1] * tr[rt<<1|1];
    }
}

node query(int l,int r,int rt,int L,int R) {
    pushdown(rt);
    if(L<=l&&r<=R) return tr[rt];
    int mid = l + r >> 1;
    node ans = node(1,0,0,1);
    if(L<=mid) ans = ans * query(l,mid,rt<<1,L,R);
    if(mid<R) ans = ans * query(mid+1,r,rt<<1|1,L,R);
    return ans;
}

int main() {
    scanf("%d%d",&n,&q);
    scanf("%s",s+1);
    build(1,n,1);
    while(q--) {
        scanf("%d",&x);
        if(x == 1) {
            scanf("%d%d",&l,&r);
            update(1,n,1,l,r);
        }
        else {
            scanf("%d%d%lld%lld",&l,&r,&a,&b);
            node c = query(1,n,1,l,r);
            ll A = (a * c.mx[0][0] % mod + b * c.mx[1][0] % mod) % mod;
            ll B = (a * c.mx[0][1] % mod + b * c.mx[1][1] % mod) % mod;
            printf("%lld %lld\n",A,B);
        }
    }
    return 0;
}

 

  

 

posted @ 2021-03-15 20:52  丿不落良辰  阅读(40)  评论(0编辑  收藏  举报