题目:abc258_c。
翻译:
问题陈述
你得到正整数 N 和 Q和一个字符串长度为N的S 由小写英文字母组成。过程 中有Q次 查询。每个查询都属于以下两种类型之一:
(1)1 x:执行以下操作连续 x 次:删除S的最后一个字符并将其附加到开头。
(2)2 x:打印S的第x个字符。
数据范围
2<=N<=500000
1<=Q<=500000
1<=x<=N
|S|=N
S由小写字母组成。
至少有一个“2 x”的问题。
Q、x都是整数。
思路:
我们刚看到这道题,肯定会想到用队列模拟整个过程,但是由于用空间太大,空间不够用,因为如果询问为“1 n”“1 n”“1 n”“1 n”,先后会出现n2个数,总代价n2=250000000000,存不下;于是采用循环队列,可是时间代价不够(参考上面的n2)。我们发现对于这个字符串,元素一经删除就会被添加回来,元素从未减少,且顺序不变,因此可以用一个变量b记录此时变更后的起始点在原字符串中的下标编号,每次做“1 x”,就将b在原来的基础上减去x,必要时做一些取模操作。教你一招使a%n不变,且1<=a<=n:(a+1)%n-1。而输出时,显而易见,就是输出原字符串的第b+x-1项。
代码:
地址:链接。
#include<bits/stdc++.h>
#define N 550000
using namespace std;
int b=0,n=0,q=0;
char s[N]={};
int calc(int num);
int main(){
scanf("%d%d%s",&n,&q,s+1);
b=1;
//输入n、q、s,并给b做初始化(没有做任何操作,原数组等于变更后的数组)
for(int i=1;i<=q;i++){
int opt=0,x=0;
scanf("%d%d",&opt,&x);
//输入询问
if(opt==1){
b=calc(b-x);
//更新b
}else{
int tmp=calc(b+x-1);
printf("%c\n",s[tmp]);
//打印相应位的字符
}
}
return 0;
}
int calc(int num){
return (num-1+n)%n+1;
//使num%n不变且1<=num<=n
}