LuoguP6553 Strings of Monody 题解

Content

给定一个长度为 \(n\) 的字符串 \(s\)(仅包含 \(1,4,5\) 三种字符,\(n\) 在本题中无需输入),有 \(m\) 个操作,每次操作给定两个整数 \(l,r\),再给定一个字符串 \(s'\),将 \(s\) 的从 \(l\)\(r\) 的子串换成 \(s'\)。请在每次操作后求出:

  1. 字符串中 \(1\) 的个数。
  2. 字符串中所有数的总和。
  3. 字符串中所有数的乘积。

以上数据都要对 \(\bf 99824353\) 取模(注意!不是 \(998244353\))。

数据范围:\(n\leqslant 10^6,m\leqslant 10^3,1\leqslant r-l+1\leqslant 10^3\)

Solution

这道题目看上去比较麻烦,其实只需要暴力模拟就可以搞定。

首先,我们可以看到,每次的变换范围不会超过 \(10^3\),所以,我们可以考虑一种 \(\mathcal{O}(m(r-l+1))\) 的算法——每次只考虑变换要变换的子串,然后更新要求的三个问题的答案。

我们可以开一个计数器 \(ans_1,ans_4,ans_5\)\(ans_i\) 表示 \(i\) 在字符串中出现的次数),每次操作就要更新着三个计数器的值,那么三个问题的答案就是 \(ans_1,ans_1+4\times ans_4+5\times ans_5,4^{ans_4}\times5^{ans_5}\)(至于第三个答案为什么不需要乘 \(1^{ans_1}\) 大家应该都弄得明白,在此不再赘述)。

这里幂次方取模明摆着用快速幂轻松搞定。

最后一点坑的就是:注意模数,不是 \(998244353\),这里应该是 \(99824353\),少了一个 \(4\)

总体来说难度不算太大,但要考虑的细节却不少。

Code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;

typedef long long ll;
ll quickpow(ll a, ll b, ll p) {
	if(p == 1)	return 0;
	ll res = 1;
	b %= p;
	for(; b; b >>= 1) {
		if(b & 1)	res = res * a % p;
		a = a * a % p;
	}
	return res;
} 
ll n, m, sum1, sum, mul = 1, aa[17];
char s[1000007];

void test1() {
	printf("%lld %lld %lld\n", aa[1], aa[4], aa[5]);
}

int main() {
	scanf("%s%d", s + 1, &m);
	n = strlen(s + 1);
	for(int i = 1; i <= n; ++i)	aa[s[i] - '0']++;
//	test1();
	while(m--) {
		char tmp[1007];
		int xx, yy;
		scanf("%d%d%s", &xx, &yy, tmp + 1);
		for(int i = 1; i <= yy - xx + 1; ++i) {
//			printf("%c %c\n", s[xx + i - 1], tmp[i]);
			aa[s[xx + i - 1] - '0']--;
			aa[tmp[i] - '0']++;
			s[xx + i - 1] = tmp[i];
		}
//		test1();
		printf("%lld %lld %lld\n", aa[1], (aa[1] + aa[4] * 4 + aa[5] * 5) % 99824353, (quickpow(4, aa[4], 99824353) * quickpow(5, aa[5], 99824353)) % 99824353);
	}
	return 0;
}
posted @ 2021-12-21 21:07  Eason_AC  阅读(64)  评论(0)    收藏  举报