题目描述
我们定义 \(F_0=a,F_i=F_{i-1}+b+F_{i-1}(i\ge 1)\),这里加法是指将字符串拼接。
给定一个字符串 \(S=F_{A_1}+F_{A_2}+\dots +F_{A_N}\),接着我们将对 \(S\) 进行一系列变换知道无法进行变换为止:
- 选择一个 \(1\le i< |S|且S_i=S_{i+1}\),删除 \(S_{i+1}\),并将 \(S_i\) 替换成下一个,这里的下一个是指变成字母表中的下一个,特别的,\(z\) 的下一个是 \(a\)。
求最终的 \(|S|\)。
思路
仔细思考一下,便会发现其实每个字符串并不会往很深处合并。因为其中每个 \(F\) 必定为 abababa...
的形式,所以两个字符串 \(F_i,F_j(i,j\ge 1)\) 最多只会合并 \(2\) 次(先把中间的两个 a
合并成 b
,在将其与旁边的 b
合并一次),而通过 \(F_0\) 合并所需的次数是 \(2^k\),而每次你都要把一个 c
一直合并到 a
,但 \(N\le 10^5\),所以不可能。
时空复杂度均为 \(O(N)\)。
代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 100001;
int t, n;
vector<char> stk;
ll ans;
string s[20];
void work() {
s[0] = 'a';
for(int i = 1; i <= 15; ++i) {
s[i] = s[i - 1] + 'b' + s[i - 1];
}
}
void Solve() {
cin >> n;
ans = 0;
stk.clear();
for(int i = 1, x; i <= n; ++i) {
cin >> x;
ans += s[x].size();
for(char c : s[min(6, x)]) {
for(; !stk.empty() && c == stk.back(); stk.pop_back()) {
c = (c - 'a' + 1) % 26 + 'a';
ans--;
}
stk.push_back(c);
}
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
work();
for(cin >> t; t--; Solve()) {
}
return 0;
}
标签:int,GYM,合并,back,stk,字符串,ans,105262
From: https://www.cnblogs.com/yaosicheng124/p/18417663