[CSP-S 2023] 消消乐
赛时
想到了一个规律,当一个字符串的头和首相等,并且中间的字符串同样可以被消除的话,那么这个大字串也就可以被消除。
虽然竭尽全力想到了这一点,不过还不知道如何实现,开始的想法是:
先使用
然而,这样的想法是大错特错的,因为有
每次枚举一个端点
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define rint register int
#define For(i, j, k) for(rint i = j; i <= k; i++)
using namespace std;
inline int read(){
int f = 1,x = 0;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-')f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void print(int x){
if(x > 9)print(x / 10);
putchar(x % 10 + '0');
}
string a;
ll ans = 0;
const int ull base = 1e7 + 7;
ull H[2000010];
signed main(){
int n = read(); cin >> a;
a = ' ' + a; H[0] = 1;
For(i, 1, n){
H[i] = H[i - 1] * base;
}
For(i, 1, n){
stack<char> s;
ull cnt = 0;
For(j, i, n){
if(!s.empty() && s.top() == a[j])
cnt -= s.top() * H[s.size()], s.pop();
else s.push(a[j]), cnt += s.top() * H[s.size()];
if(cnt == 0)
ans++;
}
}
cout << ans;
return 0;
}
- Solve 1
果然正解其实就藏在骗分之中。
Hash + 栈
使用 Hash 处理现在枚举过的无法匹配的未匹配的字串的值,如
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define rint register int
#define For(i, j, k) for(rint i = j; i <= k; i++)
using namespace std;
inline int read(){
int f = 1,x = 0;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-')f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void print(int x){
if(x > 9)print(x / 10);
putchar(x % 10 + '0');
}
string a;
stack<char> s;
ull cnt = 0;
const ull base = 1e9 + 7;
ull H[2000010];
ll ans = 0;
unordered_map<ull, ll> sum;
signed main(){
int n = read(); cin >> a;
a = ' ' + a;
H[0] = 1;
For(i, 1, n){
H[i] = H[i - 1] * base;
}
sum[0] = 1;
For(i, 1, n){
if(!s.empty() && s.top() == a[i])
cnt -= s.top() * H[s.size()], s.pop();
else
s.push(a[i]), cnt += a[i] * H[s.size()];
ans += sum[cnt];
sum[cnt]++;
}
cout << ans;
return 0;
}
- Solve 2
这就与赛时想法比较像了。
运用结论,设
那么肯定有以下的结论,令
代码如下
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define rint register int
#define For(i, j, k) for(rint i = j; i <= k; i++)
#define down(i, j, k) for(rint i = k; i <= j; --i)
using namespace std;
inline int read(){
int f = 1,x = 0;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-')f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void print(int x){
if(x > 9)print(x / 10);
putchar(x % 10 + '0');
}
ll to[2000010], dp[2000010], ans;
signed main(){
int n = read();
string a;
cin >> a;
a = ' ' + a;
For(i, 1, n){
for(int j = i - 1; j > 0; j = to[j] - 1){
if(a[j] == a[i]){
to[i] = j;break;
}
}
if(to[i])dp[i] = dp[to[i] - 1] + 1, ans += dp[i];
}
cout << ans;
return 0;
}