2019-2020 ICPC, Asia Jakarta Regional Contest K. Addition Robot(线段树 + 矩阵乘法)

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard 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…SNS=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:

  • 1 LL RR. The robot should toggle all the characters of SiSi where L≤i≤RL≤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 LL RR AA BB. 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.

扫描二维码关注公众号,回复: 11887553 查看本文章

Input

Input begins with a line containing two integers: NN QQ (1≤N,Q≤1000001≤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.

  • 1 LL RR (1≤L≤R≤N1≤L≤R≤N)
  • 2 LL RR AA BB (1≤L≤R≤N1≤L≤R≤N; 0≤A,B≤1090≤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

Copy

5 3
ABAAA
2 1 5 1 1
1 3 5
2 2 5 0 1000000000

output

Copy

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号操作, 将一个区间的内的A与B互换

2号操作询问区间内的值, 给出起始A, B

在该区间内遇到字符A, A = A + B,遇到字符B, B = B + A

问最后A, B的值为多少?

思路:

对于查询操作, 我们可以线段树套个矩阵乘法, 就可以得出答案了

对于修改操作, 我们在线段树内每个节点存两种矩阵,然后遇到修改时

交换两种矩阵即可。

\begin{bmatrix} A & B \end{bmatrix} * \begin{bmatrix} 1 &0 \\1 & 1 \end{bmatrix} = \begin{bmatrix} A + B & B \end{bmatrix}

\begin{bmatrix} A & B \end{bmatrix} * \begin{bmatrix} 1 &1 \\0 & 1 \end{bmatrix} = \begin{bmatrix} A & B + A \end{bmatrix}

#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

#ifdef LOCAL
#define debug(x) cout << "[" __FUNCTION__ ": " #x " = " << (x) << "]\n"
#define TIME cout << "RuningTime: " << clock() << "ms\n", 0
#else
#define TIME 0
#endif
#define hash_ 1000000009
#define Continue(x) { x; continue; }
#define Break(x) { x; break; }
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
struct M
{
	ll m[2][2];
	M()
	{
		memset(m, 0, sizeof m);
	}
}A, B;
M c[N * 4][2];
int lzy[N * 4];
char s[N];
M mul(M a, M b)
{
	M ans;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			for (int k = 0; k < 2; k++)
				ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j] % mod) % mod;
	return ans;
}
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
#define mid  ((L) + (R) >> 1)
void push_up(int x)
{
	c[x][0] = mul(c[ls][0], c[rs][0]);
	c[x][1] = mul(c[ls][1], c[rs][1]);
}
void pushDown(int x)
{
	if (lzy[x])
	{
		swap(c[ls][0], c[ls][1]);
		swap(c[rs][0], c[rs][1]);
		lzy[ls] ^= 1;
		lzy[rs] ^= 1;
		lzy[x] = 0;
	}
}
void build(int x, int L, int R)
{
	if (L == R)
	{
		if (s[L] == 'A')
			c[x][0] = A, c[x][1] = B;
		else
			c[x][0] = B, c[x][1] = A;
		return;
	}
	build(ls, L, mid);
	build(rs, mid + 1, R);
	push_up(x);
}
void update(int x, int L, int R, int ql, int qr)
{
	if (ql <= L && qr >= R)
	{
		swap(c[x][0], c[x][1]);
		lzy[x] ^= 1;
		return;
	}
	pushDown(x);
	if (ql <= mid)
		update(ls, L, mid, ql, qr);
	if (qr > mid)
		update(rs, mid + 1, R, ql, qr);
	push_up(x);
}
void query(int x, int L, int R, int ql, int qr, M& ans)
{
	if (ql <= L && qr >= R)
	{
		ans = mul(ans, c[x][0]);
		return;
	}
	pushDown(x);
	if (ql <= mid)
		query(ls, L, mid, ql, qr, ans);
	if (qr > mid)
		query(rs, mid + 1, R, ql, qr, ans);
	push_up(x);
}
int main()
{
#ifdef LOCAL
	freopen("D:/input.txt", "r", stdin);
#endif
	A.m[0][0] = A.m[1][0] = A.m[1][1] = B.m[0][0] = B.m[0][1] = B.m[1][1] = 1;
	int n, q;
	scanf("%d%d", &n, &q);
	scanf("%s", s + 1);
	build(1, 1, n);
	while (q--)
	{
		int op;
		cin >> op;
		if (op == 1)
		{
			int L, R;
			scanf("%d%d", &L, &R);
			update(1, 1, n, L, R);
		}
		else
		{
			int L, R, A, B;
			scanf("%d%d%d%d", &L, &R, &A, &B);
			M base, ans;
			ans.m[0][0] = ans.m[1][1] = 1;
			base.m[0][0] = A; base.m[0][1] = B;
			query(1, 1, n, L, R, ans);
			base = mul(base, ans);
			printf("%lld %lld\n", base.m[0][0], base.m[0][1]);
		}
	}
	return TIME;
}

猜你喜欢

转载自blog.csdn.net/weixin_43731933/article/details/102772187