P9753 [CSP-S 2023] 消消乐
这题想到了 50pts,想不出来怎么优化了。
50pts:考虑枚举子串左端点,模拟操作过程,直接用栈模拟,遇到相同的则删去,如果某个时刻栈为空,那么合法子串数加一。
考场上只想到为空的时候可消除,下面的性质才是关键的。因为我们枚举左端点,每次只判断了
栈的过程其实启发我们:对于两个时刻
所以我们如果知道某个时刻的出现次数
所以我们可以以左端点为
可以看出,跑一次模拟可以找到所有可消除子串的左右端点。
如果用 unordered_map,复杂度为
总结:没有发现关键性质,转化贡献的计算。
#include <bits/stdc++.h>
typedef long long ll;
#define int unsigned long long
int read() {
int x = 0, f = 1;
char c = getchar();
while(!isdigit(c)) {
if(c == '-') f = -1;
c = getchar();
}
while(isdigit(c)) {
x = (x << 3) + (x << 1) + (c - '0');
c = getchar();
}
return x * f;
}
int n, p = 131;
int ans;
int hsh[2000010];
char s[2000010];
std::stack<int> st, pos;
std::map<int, int> mp;
std::set<int> S;
void Solve() {
n = read();
std::cin >> s + 1;
mp[0]++;
S.insert(0);
for(int i = 1; i <= n; i++) {
if(!st.empty() && st.top() == s[i] - 'a') {
mp[hsh[pos.top() - 1]]++;
hsh[i] = hsh[pos.top() - 1];
st.pop();
pos.pop();
}
else {
st.push(s[i] - 'a');
pos.push(i);
hsh[i] = hsh[i - 1] * p + s[i];
S.insert(hsh[i]);
mp[hsh[i]]++;
}
}
for(int num : S) ans += mp[num] * (mp[num] - 1) / 2;
std::cout << ans << "\n";
}
signed main() {
Solve();
return 0;
}
Buy me a cup of coffee ☕.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!