首页 > 其他分享 >[题解]AT_arc113_c [ARC113C] String Invasion

[题解]AT_arc113_c [ARC113C] String Invasion

时间:2024-06-23 13:12:48浏览次数:22  
标签:arc113 String ln 题解 sum int ans 操作 lc

题意

给定一个字符串 \(S\),你可以选择一个 \(i(1 \leq i \leq |S|)\),如果 \(s_i = s_{i + 1} \neq s_{i + 2}\),就将 \(s_{i + 2}\) 设为 \(s_i\)。

问:最多能操作几次。

思路

我们可以用一个后缀和 \(s_{i,j}\) 维护 \(S_i \sim S_n\) 中与 \(j\) 不同的数量。

然后,我们可以发现一个规律:我们的操作一定是从后往前操作最优。

那么我们对于每一次操作分类讨论一下(其中 \(ln\) 表示上一次操作的位置):

  • 如果它是第一次操作,答案就加 \(s_{i + 1,S_i}\)。
  • 如果它的 \(s_i\) 为上一次操作的字符,答案就加上 \((s_{i + 1,S_i} - s_{ln,S_i}) + n - ln + 1\)。
  • 否则,答案加上 \(s_{i + 1,S_i} - s_{ln,S_i}\)。

Code

#include <bits/stdc++.h>  
#define int long long  
#define re register  
  
using namespace std;  
  
const int N = 2e5 + 10;  
int n,ln,ans;  
int sum[N][124];  
char lc;  
string s;  
//ln:上一次操作的位置  
//lc:上一次操作的字符   
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 3) + (r << 1) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
signed main(){  
    ios::sync_with_stdio(0);  
    cin.tie(0);  
    cout.tie(0);  
    cin >> s;  
    n = s.length();  
    s = ' ' + s;      
    for (re int i = n;i;i--){  
        for (re int j = 'a';j <= 'z';j++) sum[i][j] = sum[i + 1][j] + 1;  
        sum[i][s[i]]--;  
    }  
    for (re int i = n;i >= 1;){  
        if (s[i] == s[i - 1]){//判断是否需要操作   
            if (!ln) ans += sum[i + 1][s[i]];//因为没有操作过,且不能选相同的,所以要加上 sum[i + 1][s[i]]  
            else if (s[i] != lc) ans += (sum[i + 1][s[i]] - sum[ln][s[i]]) + n - ln + 1;//因为你从 ln ~ n 的位置都是为 lc(lc 不等于 s[i]),所以 lc ~ n 一定都能填上。但是不能直接加上 sum[i + 1][s[i]],需要减去 lc ~ n 的那部分   
            else ans += sum[i + 1][s[i]] - sum[ln][s[i]];// ln ~ n 是填过的,所以要减去   
            ln = i - 1;//更新   
            lc = s[i];  
            i -= 2;  
        }  
        else i--;  
    }  
    printf("%lld",ans);  
    return 0;  
}  

标签:arc113,String,ln,题解,sum,int,ans,操作,lc
From: https://www.cnblogs.com/WaterSun/p/18263292

相关文章

  • [题解]AT_arc079_c [ARC079E] Decrease (Judge ver
    思路首先,对于每一次操作,我们可以先找到最大值,然后对其操作。这样,我们可以得到单次操作时间复杂度\(\Theta(n)\)的代码,因为\(n\)很小,所以这道题时间复杂度的瓶颈在于操作的数量。那么,我们想到每一次找到最大值时,直接将其减到小于\(n\)。但是这样可能有一种问题,就是最大值......
  • [题解]AT_agc054_b [AGC054B] Greedy Division
    思路首先不难发现一个规律,当\(sum\)为奇数时不可能有解。定义\(dp_{i,j,k,0/1}\)表示A在前\(i\)个数中选出和为\(j\)的\(k\)个数,且第\(i\)个不选/选的方案数。那么,我们只需要对于第\(i\)个数的状态分类讨论就能得到状态转移方程:不选\(i\),\(dp_{i,j,k,0}=......
  • [题解]AT_abc350_g [ABC350G] Mediator
    思路有加边操作,一眼LCT。问题在于处理询问操作。首先,判断联通。如果\(x,y\)不在同一个联通块内,则一定没有答案。其次,求出\(x,y\)之间节点的数量\(num\)(包括\(x,y\))。如果\(num=3\)说明\(x,y\)之间有一个共同的节点;如果\(num=2\)说明\(x,y\)直接连接;如果\(n......
  • [题解]AT_abc343_g [ABC343G] Compress Strings
    思路首先假设有两个串\(a,b\),如果\(b\)是\(a\)的子串,且\(a\neqb\)则不需要考虑\(b\);如果\(a=b\),则如需要保留一个\(a\)。做完上述操作后,显然最终的答案是由这些串按照一定顺序拼接起来,再删掉重叠部分。例如:abbcc与ccdde拼接为abbccccdde,发现cc是重复的,所以......
  • [题解]AT_abc342_f [ABC342F] Black Jack
    思路发现自己与庄家的操作是完全独立的,所以考虑分别计算它们。首先考虑自己的情况,定义\(dp_i\)表示掷出骰子的和为\(i\)获胜的概率,并记\(f(i)\)表示\(x=i\)时就不掷的获胜概率。对于每一步我们要么掷骰子(并且掷出的值等概率的在\(1\simD\)中),要么直接结束。两种情......
  • [题解]CF855E Salazar Slytherin's Locket
    思路毒瘤数位DP题。首先,你可以用一个vector储存每一个数字出现的次数,然后用map记忆化。然后可以得到如下TLE#8的代码。因为map自带一只\(\log\)所以,考虑将map优化掉。但是,现在每一种数字可能会出现很多次,所以要用vector维护出现次数,但这样必定需要用map一......
  • [题解]CF666B World Tour
    CSP-2022S2T1弱化版。思路首先因为边权均为\(1\),所以我们可以在\(\Theta(n^2)\)的复杂度用BFS求解出任意两点\(i,j\)的最短距离\(d_{i,j}\)(如果\(i\)不能到达\(j\),则令\(d_{i,j}=-1\))。有一个贪心的结论,就是使每一条\(A\toB,B\toC,C\toD\)的路径长度......
  • [题解]CF622F The Sum of the k-th Powers
    思路首先发现\(\sum_{i=1}^{n}i^k\)是一个\(k+1\)次多项式,那么我们需要求出\(k+2\)个点才能得到唯一的一个\(f(t)=\sum_{i=1}^{t}{i^k}\)。不难通过拉格朗日插值法,将\(x=1\sim(k+2)\)的情况一一带入:\[f(n)=\sum_{i=1}^{k+2}{((\sum_{j=1}^{i}......
  • [题解]CF622D Optimal Number Permutation
    思路首先考虑答案下界,因为\((n-i)\)和\(|d_i+i-n|\)均大于等于\(0\),所以它们相乘一定大于等于\(0\)。于是考虑能不能构造出结果为\(0\)。显然当\(i=n\)时,无论\(d_i\)的值是什么,式子的结果为\(0\)。因此只需要考虑\(i\in[1,n)\)的情况。因为要使结果为......
  • [题解]CF609F Frogs and mosquitoes
    思路发现\(x\)对题目的限制较大,因此考虑先将\(x\)排序并离散化后再来考虑。不难用线段树维护\(\max_{i=l}^{r}\{x_i+len_i\}\),这样我们就可以利用类似线段树上二分的技巧得出是哪一只青蛙吃掉的蚊子。但是有可能有一只蚊子无法吃掉,我们先把它丢进一个集合里面。每有......