GYM 105262 L

题目描述

我们定义 \(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;
}
posted @ 2024-09-17 22:36  Yaosicheng124  阅读(7)  评论(0编辑  收藏  举报