首页 > 其他分享 >P8932 [JRKSJ R7] Clock Paradox 题解

P8932 [JRKSJ R7] Clock Paradox 题解

时间:2023-01-09 17:47:34浏览次数:58  
标签:子串 cnt R7 Paradox string int 题解 texttt reg

在洛谷上阅读

Part 0 题意简述

原题这场月赛我唯一AC的题

给出一个字符串 \(S\),令 \(T=S\),求使用 \(S\) 的子串插入 \(T\),将 \(T\) 变形的最少的操作次数。且字符串 \(S\) 会被修改 \(q\) 次。

具体变形:
\(S=\overline{s_1s_2…s_n}\),经过变形,使 \(T=\overline{s_1s_1s_2s_2…s_ns_n}\)。

看不懂?去看样例解释。

Part 1 题目分析

那么看过样例,我们可以知道:

对于 \(S=T=\texttt{aabc}\),我们可以分别插入子串 \(\texttt{aa}\) 和 \(\texttt{bc}\) 或分别插入子串 \(\texttt{aab}\) 和 \(\texttt{c}\),而这两种操作所用次数相同。

那么分析这两种操作的共同特点,我们可以得出每次最多可以插入的子串特征:由两段同种字符构成的字符串组成。比如,\(\texttt{aabb}\) 和 \(\texttt{ba}\) 就是这类子串,而 \(\texttt{aba}\) 或 \(\texttt{abc}\) 则不是。

而这种子串的数量,就是我们要的答案。

那么根据这种子串的特征,它又可以分成两段同种字符构成的字符串。所以,我们只需要算出由同种字符构成的子串数量 \(cnt\),次数 \(ans=\lceil\dfrac{cnt}{2}\rceil\)

Part 2 代码

根据上方分析,可以写出计算次数函数:

int calc(string s){
    int cnt=1;
    for(int i=1;i<s.length();i++)
        if(s[i-1]!=s[i])
            cnt++;
    return cnt/2+cnt%2; // 这里等同于 ceil(cnt/2.0)
}

结合其他部分,写出完整代码:

#include<iostream>
#define reg register
using namespace std;
int q;
string s;
int p;
char c;
inline int calc(string s){
    reg int cnt=1;
    for(reg int i=1;i<s.length();i++)
        if(s[i-1]!=s[i])
            cnt++;
    return cnt/2+cnt%2;
}
int main(){
    ios::sync_with_stdio(0);
    cin>>q>>s;
    cout<<calc(s)<<endl;
    while(q--){
        cin>>p>>c;
        s[p-1]=c;
        cout<<calc(s)<<endl;
    }
    return 0;
}

但是,如果你把这段代码提交上去,你只能得到 50 分。为什么?

因为这段代码的时间复杂度高达 \(O(\vert S\vert\cdot q)\),你只能通过前 3 个 Subtask。

Part 3 优化

仔细观察上一段代码你就会发现它做了很多没用的事情。
在修改字符串时,子串数量 \(cnt\) 只与 \(s_{p-1}\),\(s_p\),\(s_{p+1}\) 和 \(c\) 有关。所以我们在每次修改后只需要维护上一次的 \(cnt\) 即可。

这里的维护代码:

cnt=cnt-((int)(s[p-2]!=s[p-1])+(int)(s[p-1]!=s[p]))+((int)(s[p-2]!=c)+(int)(c!=s[p]));

原理就是将原来函数内的循环展开,这里不过多解释,请自行思考。也可以修改函数使它支持单点维护但是我懒得写

最终代码:

#include<iostream>
#define reg register
using namespace std;
int q;
string s;
int p;
char c;
int count(string s){
    reg int cnt=1;
    for(reg int i=1;i<s.length();i++)
        if(s[i-1]!=s[i])
            cnt++;
    return cnt;
}
int main(){
    ios::sync_with_stdio(0);
    cin>>q>>s;
    reg int cnt=count(s);
    cout<<cnt/2+cnt%2<<endl;
    while(q--){
        cin>>p>>c;
        cnt=cnt-((int)(s[p-2]!=s[p-1])+(int)(s[p-1]!=s[p]))+((int)(s[p-2]!=c)+(int)(c!=s[p]));
        s[p-1]=c;
        cout<<cnt/2+cnt%2<<endl;
    }
    return 0;
}

标签:子串,cnt,R7,Paradox,string,int,题解,texttt,reg
From: https://www.cnblogs.com/WorldHim/p/solution-luogu-p8932.html

相关文章

  • Educational Codeforces Round 141 (Rated for Div. 2) A-C题解
    比赛链接A、MakeitBeautiful一种构造方法:按照从大到小的顺序构造,可以发现前缀和永远大于当前值。但是需要特判存在两个最大值的情况。只需要将最小值与第二位交换位置......
  • P5999 [CEOI2016] kangaroo 题解
    分析一个妙妙的trick。首先原题可以转化成求有多少\(1\simn\)的排列\(p\)满足\(\foralli\in(1,n)\),\(p_i\)两边的数同时小于或大于\(p_i\),且\(p_1=s,p_n=t\)......
  • WC 2018 题解
    A若干套路拼起来的胖题。设这三棵树分别是\(T_1,T_2,T_3\)。沿用“CTSC2017暴力写挂”的思路,对第一棵树点分治,此时要处理的是以\(u\)为中心的一块在\(T_1\)上的连......
  • CF652F 题解
    题意传送门在一个长度为\(m\)的圆环上有\(n\)只初始位置互不相同的蚂蚁,每只蚂蚁的速度都为\(1\),初始方向为顺时针或逆时针;两只运动方向不同的蚂蚁相遇时会调转方向,......
  • Codeforces 1671 F Permutation Counting 题解
    题目链接把\(p_i>p_{i+1}\)的位置个数称为间隔数首先想到一个暴力做法。从小到大挨个添加1-n中的每个数,注意到添加数i时,只能添加到当前序列的最后11个位置中,否则逆序对数......
  • 2018年各大赛事题解
    大多数题解都是口胡,不保证正确性,有错请指出,谢谢。CQOI2018除了“交错序列”和“九连环”两道数学题以外,全是板子题,遭不住了。破解D-H协议BSGS板子题,时间复杂度\(\m......
  • Atcoder ABC284 前五题题解
    ABC284A-SequenceofStrings题意:有n个字符串\(s_1,s_2,s_3,...,s_n\),要求按\(n,n-1,n-2,...,1\)的顺序输出样例:输入3TakahashiAokiSnuke输出......
  • Codeforces 1305 F Kuroni and the Punishment 题解 (随机算法)
    题目链接首先注意到每个数最多操作1次就能让他变成2的倍数,所以答案\(\len\)。如果我们能枚举[1,1e12]中所有的质数,并对每个质数p求出把数组中所有数都变成它的倍数的最少......
  • 【题解】P5666 [CSP-S2019] 树的重心
    感觉对重心的理解更直观了一点。题意求一棵树上删去每一条边后两侧子树重心的编号和。\(n\leq3\times10^5\)思路神奇的清真数论。首先这里有一步很妙的操作:把整......
  • LeetCode 887. 鸡蛋掉落-题解分析
    题目来源887.鸡蛋掉落题目详情给你k枚相同的鸡蛋,并可以使用一栋从第1层到第n层共有n层楼的建筑。已知存在楼层f,满足 0<=f<=n,任何从高于f的楼层落......