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

P9753 [CSP-S 2023] 消消乐

好久之前做过的题,因为我们的赛出到了所以把题解也补一下。

Ref: P9753 [CSP-S 2023] 消消乐 题解 - SpadeA261

\(f_i\) 表示以 \(i\) 结尾的答案。则 \(f_i\)\(f_{g_i}\) 转移而来。其中 \(g_i\)\(i\) 之前使 \(s[i,p]\) 合法的最大 \(p\)

对于每个 \(i\) 循环向前跳即可。

时间复杂度 \(O(|\Sigma|n)\),空间复杂度 \(O(n)\)。其中 \(|\Sigma|=26\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e6+5;
int n,f[N],g[N],ans;
string s;
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>s;
	s=' '+s;
	for(int i=1,j;i<=n;i++){
		for(j=i-1;j>0&&s[i]!=s[j];j=g[j]-1);
		if(s[i]==s[j]){
			g[i]=j;
			f[i]=f[j-1]+1;
			ans+=f[i];
		}
	}
	cout<<ans<<"\n";
	return 0;
}

考虑优化时间。

我们令 \(h_i=g_i-1\),则画出来是这样的:

image

我们用 \(a_{i,c}\) 表示使得 \([p,i]\) 合法且 \(a_{p+1}=c\) 的最大的 \(p\)

每次修改 \(a_{i,s_i}\) 即可。

但是这样还是 \(O(|\Sigma|n)\) 的,考虑用路径压缩,记录 \(i\) 所在的链头为 \(to_i\),每次对 \(a\) 的修改和查询都在链头进行。

时间复杂度 \(O(n)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e6+5,C=26;
int n,ans,f[N],a[N][C],to[N];
string s;
signed main(){
	ios::sync_with_stido(0),cin.tie(0),cout.tie(0);
	cin>>n>>s,s=' '+s;
	for(int i=1;i<=n;i++){
		to[i]=i;
		int p=a[to[i-1]][s[i]-'a'];
		if(p) to[i]=to[p-1],f[i]=f[p-1]+1;
		a[to[i]][s[i]-'a']=i,ans+=f[i];
	}
	cout<<ans<<"\n";
	return 0;
}
posted @ 2025-10-29 08:02  Sinktank  阅读(14)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.