首页 > 其他分享 >P9192 Pareidolia 题解

P9192 Pareidolia 题解

时间:2024-09-22 21:46:43浏览次数:11  
标签:P9192 匹配 lgo int 题解 rhs mid res Pareidolia

Statement

给串 \(t\),定义 \(B(s)\) 为 \(s\) 删一些字符后能出现最多多少个 bessie,\(A(t)\) 表示对 \(t\) 的所有子串 \(s\) 求 \(B(s)\) 的和,有 \(q\) 次单点修改,每次改完输出 \(B(s)\).

Solution

动态 dp,但是带矩乘 \(6^3\) 常数,不好.

还是考虑分治咋做.

现在有区间 \([l,mid],[mid+1,r]\)

对于一个跨过中点的区间 \([x,y]\),有个贪心策略:

\(x\to mid\) 这段贪心的匹配 bessie(遇到一个匹配一个),

\(y\to mid+1\) 这段从右往左贪心的匹配 bessie(遇到一个匹配一个,\(\texttt e\to\texttt i\to\texttt s\to\cdots\))

如果左边匹配完还多余的一段,与右边匹配完还多余的一段,可以凑成一个 bessie,答案加一。

例如 \(x\to mid\) 左边这段最后匹配到 bes,\(y\to mid+1\) 右边这段最后匹配到 ssie,那么答案会多一。

于是答案 \(=\) \([x,mid]\) 的答案 \(+\) \([mid+1,y]\) 的答案 \(+\) \([\)是否多贡献 \(1\)\(]\)

如果固定 \(x\)、移动 \(y\),“\([x,mid]\) 的答案”对总答案的贡献是 “\([x,mid]\) 的答案” \(\times\) \((r-(mid+1)+1)\)

那么不固定 \(x\)、移动 \(y\),“\([x,mid]\) 的答案”对总答案的贡献是 “所有 \(x\) 对应的 \([x,mid]\) 的答案之和” \(\times\) \(R.len\)

类似的,“\([mid+1,y]\) 的答案”对总答案的贡献是 “所有 \(y\) 对应的 \([mid+1,y]\) 的答案之和” \(\times\) \(L.len\)

那么 \([\)是否多贡献 \(1\)\(]\) 对总答案的贡献是多少呢?

可以通过:

  • 左区间:每个后缀贪心的匹配,最后匹配到 bessie 每个位置的后缀数
  • 右区间:每个前缀贪心的匹配,最后匹配到 bessie 每个位置的前缀数

求出

如何求出这两个东西呢?……

通过一堆分析发现,我们需要维护这些东西:

  • rval:每个后缀 \(\texttt b\to\texttt e\to\texttt s\to\cdots\) 贪心地匹配,匹配完 bessie 的次数之和
  • lval:每个前缀 \(\texttt e\to \texttt i\to\texttt s\to\cdots\) 贪心地匹配,匹配完 bessie 的次数之和
  • len:区间长度
  • rcnt[8]:每个后缀 \(\texttt b\to\texttt e\to\texttt s\to\cdots\) 贪心地匹配,最后匹配到 bessie 每个位置的后缀数
  • lcnt[8]:匹配到 bessie 每个位置的前缀数
  • rtrans[8]:从左到右,从 bessie 第 \(i\) 个位置出发贪心地匹配,最后匹配到 bessie 哪个位置.
  • ltrans[8]:从右到左,从第 \(i\) 个位置出发贪心地匹配,匹配到哪个位置.
  • rgo[8]:从左到右,从第 \(i\) 个位置出发贪心地匹配,匹配到的轮数.
  • lgo[8]:从右到左,匹配的轮数.

得出他们的定义后,合并你是可以手推的。一次合并 \(O(6)\)(我知道这不严谨,但是我就要这么写 ^-^)

在线段树上做就能支持单点改了。。。

Code

push_up 写了巨大麻烦分讨

#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
#define mem(a) memset(a, 0, sizeof(a))
#define Mem(a) memset(a, -1, sizeof(a))
typedef long long ll;
const int N = 2e5 + 10;
string s;
int n, m;

struct Item {
	ll rcnt[6], lcnt[6], rtrans[6], ltrans[6], rgo[6], lgo[6];
	ll len, rval, lval, ans;
	Item() {
		mem(rcnt), mem(lcnt), mem(rgo), mem(lgo), Mem(rtrans), Mem(ltrans);
		len = rval = lval = ans = 0;
	}
	Item(char c) {
		(*this) = Item(), len = 1;
		auto Set = [&](int x) {
			ltrans[x] = rtrans[x] = x, rgo[x] = lgo[x] = 1;
		};
		if (c == 'b') rcnt[0] = 1, Set(0);
		if (c == 'e') lcnt[5] = 1, Set(1), Set(5);
		if (c == 's') Set(2), Set(3);
		if (c == 'i') Set(4);
	}
	Item operator+ (const Item& rhs) const {
		Item res;
		res.len = len + rhs.len;
		res.ans = ans + rhs.ans + rval * rhs.len + rhs.lval * len;
		ll sum = 0;
		rep(i, 0, 4) {
			sum += rhs.lcnt[i + 1];
			res.ans += sum * rcnt[i];
		}
		rep(i, 0, 5) {
			if (rtrans[i] == -1) {
				res.rtrans[i] = rhs.rtrans[i];
				res.rgo[i] = rhs.rgo[i];
			} else {
				int p = rtrans[i];
				if (rhs.rtrans[(p + 1) % 6] == -1) {
					res.rtrans[i] = p;
					res.rgo[i] = rgo[i];
				} else {
					res.rtrans[i] = rhs.rtrans[(p + 1) % 6];
					res.rgo[i] = rgo[i] + rhs.rgo[(p + 1) % 6];
				}
			}
			if (rhs.ltrans[i] == -1) {
				res.ltrans[i] = ltrans[i];
				res.lgo[i] = lgo[i];
			} else {
				int p = rhs.ltrans[i], q = (p + 5) % 6;
				if (ltrans[q] == -1) {
					res.ltrans[i] = p;
					res.lgo[i] = rhs.lgo[i];
				} else {
					res.ltrans[i] = ltrans[q];
					res.lgo[i] = rhs.lgo[i] + lgo[q];
				}
			}
			res.rcnt[i] += rhs.rcnt[i];
			res.lcnt[i] += lcnt[i];
		}
		res.rval = rhs.rval + rval, res.lval = lval + rhs.lval;
		ll r1 = 0, l2 = 0;
		rep(i, 0, 5) {
			int p = rhs.rtrans[(i + 1) % 6];
			if (p != -1) res.rcnt[p] += rcnt[i];
			else res.rcnt[i] += rcnt[i];
			r1 += rcnt[i];
			if (i <= 4) {
				int cnt = (i + 1 + rhs.rgo[(i + 1) % 6]) / 6;
				res.rval += rcnt[i] * cnt;
			} else {
				int cnt = rhs.rgo[(i + 1) % 6] / 6;
				res.rval += rcnt[i] * cnt;
			}
			p = ltrans[(i + 5) % 6];
			if (p != -1) res.lcnt[p] += rhs.lcnt[i];
			else res.lcnt[i] += rhs.lcnt[i];
			l2 += rhs.lcnt[i];
			if (i >= 1) {
				int cnt = (6 - i + lgo[(i + 5) % 6]) / 6;
				res.lval += rhs.lcnt[i] * cnt;
			} else {
				int cnt = lgo[(i + 5) % 6] / 6;
				res.lval += rhs.lcnt[i] * cnt;
			}
		}
		if (rhs.rgo[0]) res.rcnt[(rhs.rgo[0] - 1) % 6] += len - r1, res.rval += (len - r1) * (rhs.rgo[0] / 6);
		if (lgo[5]) res.lcnt[(6 - lgo[5] % 6) % 6] += rhs.len - l2, res.lval += (rhs.len - l2) * (lgo[5] / 6);
		return res;
	}
} f[N << 2];

#define lc (u << 1)
#define rc ((u << 1) | 1)
#define mid ((l + r) >> 1)

void up(int u) {
	f[u] = f[lc] + f[rc];
}
void build(int u, int l, int r) {
	if (l == r) return (void)(f[u] = Item(s[l - 1]));
	build(lc, l, mid), build(rc, mid + 1, r), up(u);
}
void upd(int u, int l, int r, int x, char c) {
	if (x < l || r < x) return;
	if (l == r) return (void)(f[u] = Item(c));
	upd(lc, l, mid, x, c), upd(rc, mid + 1, r, x, c), up(u);
}

#undef lc
#undef rc
#undef mid

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr);
	cin >> s >> m, n = s.length(), build(1, 1, n), cout << f[1].ans << '\n';
	while (m--) {
		int p;
		char ch;
		cin >> p >> ch;
		upd(1, 1, n, p, ch);
		cout << f[1].ans << '\n';
	}
	return 0;
}

标签:P9192,匹配,lgo,int,题解,rhs,mid,res,Pareidolia
From: https://www.cnblogs.com/laijinyi/p/18425957

相关文章

  • P3703 树点涂色 题解
    Statement树,每个点有一个颜色,初始每个点颜色互不相同到根链涂上新颜色链颜色数\(u\)子树内点\(v\)到根路径的最多颜色数Solution首先,相同颜色的点一定构成一条从下往上的链考虑LCT,维护一个性质:一条实链的点的颜色相同.于是\(u\)到根的颜色数\(=\)\(u\)到根的虚......
  • 最长公共子串 题解
    StatementQ7.1.2.4,时限4s给一个串,定义\(\mathrm{LCS}\)为最长公共子串长度,\(q\)次询问,每次给出\(l,r\),求\[\operatorname{xor}_{i=1}^{r-l+1}\{i+\mathrm{LCS}(S[l,l+i-1],S[l+i-1,r])\}\]\(n\le10^5,q\le30\)Solutiontag:SA,线段树维护分治结构,orzhunction题目就是......
  • BZOJ 2555 = P5212 SubString 题解
    Statement给你一个字符串 \(\text{init}\),要求你支持两个操作:在当前字符串的后面插入一个字符串;询问字符串 \(s\) 在当前字符串中出现了几次?(作为连续子串)你必须在线支持这些操作。Solutionextend中link[cur]=q,相当于link,链加新建copy那里,相当于link,cut,链加询......
  • 2024 秋季模拟赛题解
    2024秋季模拟赛题解CSP-S模拟赛2024.9.8CSP-S模拟赛28T1签到题。对\(b\)分解质因数后便容易求解。T2考虑枚举\(\gcd(S)\)的取值\(x\),则\(\operatorname{lcm}(S)=m-x\)。那么同时变形\(\gcd\)和\(\operatorname{lcm}\)变为\(\gcd(S)=1,\operatorname{lcm}......
  • BZOJ 3277 串 题解
    Statement给 \(n\) 个串,问每个串有多少子串是所有 \(n\) 个串中至少 \(k\) 个串的子串。Solution1%%注意到\(\text{LCP}\)在后缀排序后一定是连续的一段,包含一个串的区间是连续的先预处理出对于所有左端点\(l\),最左的\(r\)满足\([l..r]\)中出现了至少\(k\)个......
  • BZOJ 4310 跳蚤 题解
    Statement把\(S\)分成不超过\(k\)段,使每段的最大子串中的最大串最小。输出这个串。Solution按排名二分这个串,check中从右往左贪心地划分,需要实现\(O(1)\)比较两个子串大小。#include<bits/stdc++.h>usingnamespacestd;#definerep(i,j,k)for(inti=(j);i<......
  • BZOJ 4545 DQS 的 trie 题解
    Statement维护一棵树,边权\(\in\{\texttta,\textttb,\textttc\}\),根为\(1\),定义这棵树的子串为从\(1\)走到所有点构成的字符串的所有后缀,需要支持以下操作:问当前树的本质不同子串数给一个点添加一棵子树问一个串在当前树中作为子串的出现次数Solution直接广义SAM+......
  • 力扣72-编辑距离(Java详细题解)
    题目链接:力扣72-编辑距离前情提要:因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。dp五部曲。1.确定dp数组和i下标的含义。2.确定递推公式。3.dp初始化。4.确定dp的遍历顺序。5.如果没有ac打印dp数组利于debug。每一个dp题目如果都用这五步分析清楚,那么......
  • ABC372 F 题解
    F-TeleportingTakahashi2先把问题转化一下:把环断开成链,复制\((K+1)\)层,每走一步就相当于前进一层:可以想到一个简单的dp:设\(f(i,j)\)表示走到第\(i\)层第\(j\)个位置的方案数。初始化:\(f(0,1)=1\),其它均为\(0\),表示Takahashi从第\(0\)层的\(1\)位置......
  • 【题解】「Public NOIP Round #2」找零
    【题解】「PublicNOIPRound#2」找零[官解](PublicNOIPRound#2题解-博客-Qingyu的博客(pjudge.ac))Tag:背包、dp凸优化决策点单调触碰到知识点盲区了,所以来写几笔。首先,由于我们只关心最终状态下\(1\)的最多个数,其实有用的面值只有\(5,1\)(其她的可以当成若干......