B:
给定一个由小写字母组成的字符串S。你要逐个执行Q个操作。每个操作可以是以下两种类型之一:
修改:给定一个整数x。根据x的值修改字符串S。如果x是正数,则将S中最左边的x个字母移到S的右侧;如果x是负数,则将S中最右边的|x|个字母移到S的左侧。
查询:给定一个正整数x。请回答当前字符串S中第x个字母是什么。
输入描述:
输入共有Q+2行。第一行是字符串S。第二行是整数Q。接下来的Q行表示Q个操作。在执行这些操作时,请按照输入中的顺序进行。
输入中的每个操作由一个字符c和一个整数x表示。如果c='M',则该操作是一个修改操作,即根据x的值重新排列字符串S;如果c='A',则该操作是一个查询操作,即回答当前字符串S中第x个字母是什么。
• 2≤|S|≤2×10^6(|S|表示字符串S的长度)
• S由小写字母组成
• 1≤Q≤8×10^5
• c='M'或'A'
• 如果c='M',则1≤|x|<|S|
• 如果c='A',则1≤x≤|S|
• 输入中至少有一个操作满足c='A'
输出描述:
对于每个查询操作,请输出一个字母,表示操作的答案。输出的顺序应与输入中操作的顺序相匹配。
输入
nowcoder 6 A 1 M 4 A 6 M -3 M 1 A 1
输出
n o w
刚看到这一题,我脑子里第一个想法就是如果c=='M',且x>0,直接用substr接口取出前x个子串,然后把原字符串的前x个子串用erase删除,再用+=号让字串与原字符串相加,这样就得到了修改后的字符串,同理如果x是负数也是这样的操作,但结果却报错了(~~呜呜u)
很明显,复杂度太高,因为substr的复杂度为n,加上外面一层for循环,复杂度直接达到了o(n^2);
后面问了一些朋友,发现可以把这个字符串视为一个环,然后创建一个下标变量p来确定更改后的字符串,如x为正值的修改,可以先设p=0;此时字符串首地址为p+x;但还要进行求余,防止数组下标越界,p=(p+x)%lenth;当x为负值时,p=(p+lenth+x)%lenth;
其实当修改时x为正值时,p=(p+x)%lenth;与p=(p+lenth+x)%lenth;的下标时一样的;所以无论x是正还是负,都可以直接p=(p+lenth+x)%lenth;
这样复杂度就为o(1);
查找时:访问的下标是p=(p+x-1)%lenth;
但提交的时候还是超时了1ms,(大无语~),发现是卡常了;因为我是用cin cout进行输入和输出的,所以效率就比scanf和printf慢很多;
发现是卡常的问题:
卡常数,又称底层常数优化,特指在 OI/ACM-ICPC 等算法竞赛中针对程序基本操作进行的底层优化,一般在对程序性能要求较为严苛的题目或是在算法已经达到理论最优时间复杂度时使用,有时也用于非正解的强行优化。 ——百度百科
加上这句话就解决了
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
关于一些输入和输出中的卡常问题,可以通过下面这个链接了解;
浅论 OI 中的卡常技巧(基本完成) - wYYSZL的文章 - 知乎 https://zhuanlan.zhihu.com/p/608989466
下面这个也可以
竞赛中应该用scanf还是cin? scanf&printf与cin&cout的比较+快读快写_快读和scanf-CSDN博客
在这里另外介绍一下关于sizeof和strlen函数的区别: