P9753 [CSP-S 2023] 消消乐 题解

考前天天祈祷不考串串和数数结果靠这个翻盘好好好。

为什么都说 D 比 B 简单。

题目传送门

Solution

按照一般的计数 dp 的状态设计,我们不妨设 fi 为以 i 为右端点的合法子串个数。

最后答案是 i=1nfi

考虑合法的子串有哪几种形式,不妨设 A,B 均合法,以及单个字符 c

那么合法的字串只可能为一下四种形式:

  1. A

  2. AB

  3. cAc

  4. cc

其他所有的都可以规约到这四种。

lsti 为最大的 j 满足 s[i,j] 是合法子串的 j

那我们的转移便是 fi=flsti1+1

加 1 是因为要把自己算上,前面的 flsti1 是在算第二类子串的个数。

对于 lsti 的计算直接采取暴力跳的方式即可,考虑每次跳的一定是不同字符,总复杂度是 O(26n)

code

#include <bits/stdc++.h>
#define rep(i, j, k) for(int i = (j); i <= (k); i ++)
#define per(i, j, k) for(int i = (j); i >= (k); i --)
#define fi first
#define se second
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e6 + 5, INF = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
int n;
string s;
LL f[N];
int lst[N];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> s;
	s = " " + s;
	rep(i, 1, n) {
		lst[0] = -1;
		if(s[i] == s[i - 1]) lst[i] = i - 1;
		else {
			lst[i] = -1;
			int j = i - 1;
			while(lst[j] != -1) {
				j = lst[j] - 1;
				if(s[i] == s[j]) {
					lst[i] = j;
					break;
				}
			}
		}
	}
	rep(i, 1, n) if(lst[i] != -1) f[i] = f[lst[i] - 1] + 1;
	LL res = 0;
	rep(i, 1, n) res += f[i];
	cout << res << '\n'; 
	return 0;
}
posted @   Svemit  阅读(651)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
主题色彩