首页 > 其他分享 >CF578E Walking! 题解

CF578E Walking! 题解

时间:2024-07-26 19:18:23浏览次数:5  
标签:Walking str 题解 LL CF578E back vv cnt 序列

Description

  • 给定一个长度为 \(n\) 的只包含 L,R 的字符串 \(s\)。
  • 构造一个 \(n\) 排列 \(p\) 满足 \(s[p_i] \ne s[p_{i+1}](1 \le i < n)\)。
  • 最小化 \(p\) 中 \(p_i > p_{i+1}(1 \le i < n)\) 的数量。
  • \(n \le 10^5\),数据保证有解。

Solution

考虑把 \(p\) 中的每个极长连续上升子序列拿出来,显然这些子序列为 \(1,2,\ldots,n\) 的一个划分,使得每个子序列一定是 LR 交错出现。

所以第一问的答案为把 \(1,2,\ldots,n\) 划分成最少的子序列数\(-1\),使得每个子序列是 LR 交错出现。

有一个显然的贪心策略是从前往后扫,不妨设 \(s_i\) 为 L,如果 \(s_i\) 能找到末尾与其不同的子序列就把它加到那个子序列末尾,如果找不到就创建一个新的子序列。

证明就考虑如果能找到但是不加,就说明当前答案会 \(+1\),如果加了顶多是后面的一个 R 找不到 L 与其配对,也只会 \(+1\),并且在这之前答案一直更优。

然后需要构造方案,用 \(cnt_{ij}\) 表示开头为 \(i\),末尾为 \(j\) 的子序列数量。

容易发现当 \(cnt_{LR},cnt_{RL}\neq 0,cnt_{LL}=cnt_{RR}=0\) 时是无法直接构造方案的,这时可以任意取一对 LR 和 RL 的序列,把末尾更靠后的那个序列的末尾放到另一个序列的末尾,这样就有了 LL 和 RR。

注意到 \(|cnt_{LL}-cnt_{RR}|\leq 1\),不妨设 \(cnt_{LL}\geq cnt_{RR}\),可以构造:LR、LR、...、LR、LL、RL、RL、...、RL、RR、LL、RR、LL、...

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

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 1e5 + 5;

int n, tot;
std::string str;
std::vector<int> vec[2], vv[kMaxN], id[2][2];

void fix() {
  int x = id[0][1].back(), y = id[1][0].back();
  id[0][1].pop_back(), id[1][0].pop_back();
  if (vv[x].back() < vv[y].back()) std::swap(x, y);
  vv[y].emplace_back(vv[x].back()), vv[x].pop_back();
  id[str[vv[x].front()] == 'R'][str[vv[x].back()] == 'R'].emplace_back(x);
  id[str[vv[y].front()] == 'R'][str[vv[y].back()] == 'R'].emplace_back(y);
}

void print(int x) {
  for (auto i : vv[x]) std::cout << i << ' ';
}

void dickdreamer() {
  std::cin >> str;
  n = str.size(); str = " " + str;
  for (int i = 1; i <= n; ++i) {
    int c = (str[i] == 'R');
    if (!vec[c ^ 1].size()) {
      vec[c].emplace_back(++tot);
      vv[tot] = {i};
    } else {
      int t = vec[c ^ 1].back(); vec[c ^ 1].pop_back();
      vv[t].emplace_back(i), vec[c].emplace_back(t);
    }
  }
  std::cout << tot - 1 << '\n';
  for (int i = 1; i <= tot; ++i)
    id[str[vv[i].front()] == 'R'][str[vv[i].back()] == 'R'].emplace_back(i);
  if (id[0][1].size() && id[1][0].size() && !id[0][0].size() && !id[1][1].size()) fix();
  int o = 0;
  if (id[0][0].size() < id[1][1].size()) o = 1;
  for (auto x : id[o][o ^ 1]) print(x);
  if (id[o][o].size()) print(id[o][o].front());
  for (auto x : id[o ^ 1][o]) print(x);
  for (int i = 0; i < (int)id[o ^ 1][o ^ 1].size(); ++i) {
    print(id[o ^ 1][o ^ 1][i]);
    if (i + 1 < (int)id[o][o].size()) print(id[o][o][i + 1]);
  }
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:Walking,str,题解,LL,CF578E,back,vv,cnt,序列
From: https://www.cnblogs.com/Scarab/p/18326070

相关文章

  • 小信小友逛庙会 题解
    题目id:9774题目描述小信与小友相约逛庙会。但是庙会人很多,他们走散了。庙会能表示成\(n×m\)的矩阵,小信在'\(C\)',小友在'\(D\)','\(.\)'表示能走,'#'表示店铺(也就是不能走)。每分钟,小信可以往\(8\)个方向移动一格,而小友可以移动一次或者两次,每次可以往\(4\)个方向(上下左右)移动一......
  • 开心消消乐 题解
    题目id:8578题目描述\(A\)酱最近在玩开心消消乐,由于是异次元的游戏,所以规则可能和地球上的有所不同。开心消消乐是一个在大圆环上进行的游戏,环上有若干个宝石,每颗宝石都有自己的积分,由于消消乐是一个三消游戏,我们每次可以挑选其中一个宝石消去,消去宝石的积分为他的积分和左右相......
  • CF1988F 较草题解
    \[\begin{aligned}&f_{i,j,k},g_{i,j,k}\to(i\text{permutation},j\text{premaxorsufmax},k(a[l]>a[l-1]))\\&\text{Initialize:}f_{1,1,0}=g_{1,1,0}=1\\&\text{Transferforf,g}\\&f_{i,j,k}=f_{i-1,j-1,k-1......
  • 参天大树 题解
    题目id:5602题目描述丛林中矗立着一棵参天大树,高度为\(y\)。大树\(2\simp\)高度处,每个位置都有一只蚱蜢。一只蚱蜢如果在\(x\)高度处,那么它可以跳到\(2x、3x、4x、......\)等任意一个\(x\)的倍数处。你想在\(2\simy\)高度范围内,找到一个尽可能高且不会有任何蚂蚱能跳到的位......
  • 力扣题解1-两数之和
    LeetCode第一题"两数之和"(TwoSum)问题分析过程:这个问题可以通过多种方法解决,包括暴力解法和使用哈希表的解法。以下是详细的分析过程:暴力解法:遍历数组中的每一对元素,检查它们的和是否等于目标值。时间复杂度是O(n^2),其中n是数组的长度。使用哈希表:使用一......
  • Pag动画:umi+libpag+copy-webpack-plugin实现及问题解决
    1、package.json添加如下,安装依赖:"libpag":"^4.2.84","copy-webpack-plugin":"9.1.0",为什么是写死的旧版本,后面解释2、使用的方法,这里只是一个小示例,具体如何使用看个人(这里主要是想记录过程中出现的问题及解决方式): constinit=async()=>{   constPag......
  • 优美子数列2 题解
    题目id:8628题目描述数学家小\(Q\)得到了一个长度为\(N\)的数列\(a_n\)。小\(Q\)的幸运数字是\(k\),所以他认为,若一个子数列\(a_l,a_{l+1},...,a_r\)的和为\(k\)的倍数,则该子数列是优美子数列。小\(Q\)现在想考考你,\(a_n\)里有多少个优美子数列呢?前置知识前缀和、桶解题思路......
  • 近期题解(2024.7.26)
    CF1070AFindaNumber一个朴素的想法是设\(dp_{x,y}\)表示模\(d\)为\(x\)且和为\(y\)的最小值,那么答案就是\(dp_{0,s}\)。自然初始状态为\(dp_{0,0}=0\),但是我们发现这个转移关系是带环的,所以说要把这个dp换成最短路。直接从\((0,0)\)为源跑一遍bfs即可,时间复......
  • 题解:Codeforces Round 961 (Div. 2) C
    C.Squaringtimelimitpertest:2secondsmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputikrpprppfoundanarray\(a\)consistingofintegers.Helikesjustice,sohewantstomake\(a\)fair —thatis,makeitnon......
  • 魔术上网导致Github push 443 问题解决方法
    问题描述使用“kexue上网”工具后,在IDEA中push代码到github时,报错:Failedtoconnecttogithub.comport443:Operationtimedout。同时,使用浏览器访问github也会出现无法访问,偶尔能访问的情况。解决办法gitconfig--globalhttp.proxyhttp://127.0.0.1:1087git......