1. 程式人生 > 其它 >LuoguP6553 Strings of Monody 題解

LuoguP6553 Strings of Monody 題解

LuoguP6553 Strings of Monody 題解

Content

給定一個長度為 \(n\) 的字串 \(s\)(僅包含 \(1,4,5\) 三種字元,\(n\) 在本題中無需輸入),有 \(m\) 個操作,每次操作給定兩個整數 \(l,r\),再給定一個字串 \(s'\),將 \(s\) 的從 \(l\)\(r\) 的子串換成 \(s'\)。請在每次操作後求出:

  1. 字串中 \(1\) 的個數。
  2. 字串中所有數的總和。
  3. 字串中所有數的乘積。

以上資料都要對 \(9982\color{red}\text{43}\color{black}\text{53}\) 取模(注意!不是 \(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;
}