题目描述
难度分:943
最初S=1。
输入q(≤6×105)和q个操作,操作的输入格式如下:
-
如果输入的是
1 x
,把x加到S末尾。其中1≤x≤9。 -
如果输入的是
2
,删除S的第一个数字。 -
如果输入的是
3
,把S视作一个整数,输出它模998244353的结果。
输入样例1
3
3
1 2
3
输出样例1
1
12
输入样例2
3
1 5
2
3
输出样例2
5
输入样例3
11
1 9
1 9
1 8
1 2
1 4
1 4
1 3
1 5
1 3
2
3
输出样例3
0
算法
队列模拟
用队列来存储S,初始情况下,队列中只有一个1。记队列中元素所表示的数字为num,三种操作按照如下规则:
- 如果是插入操作,则有num=(10×num%mod+x)%mod,并将x尾插进队列。
- 如果是删除操作,则弹出队头元素d,此时d代表的应该是d×10sz,其中sz为队列弹出d后的大小。则有num=(num−d×10sz+mod)%mod。
- 打印操作直接打印num即可。
为了快速进行操作2,可以先预处理出一个10的整次幂数组p,p[i]表示10i%mod。
复杂度分析
时间复杂度
令p[0]=1,然后线性遍历幂次来计算p[i],因此预处理出10的整次幂数组p的时间复杂度为O(n)。记操作次数为q的规模,队头弹出和队尾插入的时间复杂度都是O(1)的,每个操作里面的计算也都是O(1)的,因此算法整体的时间复杂度就是O(n+q)。
空间复杂度
空间消耗的痛点就是队列和数组p,最差情况下没有弹出操作,全是队列的插入操作,额外空间复杂度为O(n+q)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
const int MOD = 998244353, N = 600010;
LL p[N];
LL fast_power(LL a, LL k, LL p) {
LL res = 1 % p;
while(k) {
if(k & 1) res = (LL)res*a%p;
a = (LL)a*a%p;
k >>= 1;
}
return res;
}
int main() {
if(!p[0]) {
// 只预处理一次
p[0] = 1;
for(int i = 1; i <= N - 10; i++) {
p[i] = p[i - 1]*10%MOD;
}
}
int Q;
scanf("%d", &Q);
LL num = 1;
queue<int> q;
q.push(1);
while(Q--) {
int t;
scanf("%d", &t);
if(t == 1) {
int x;
scanf("%d", &x);
q.push(x);
num = (num*10%MOD + x) % MOD;
}else if(t == 2) {
int d = q.front();
q.pop();
int sz = q.size();
num = (num - p[sz]*d%MOD + MOD) % MOD;
}else {
printf("%lld\n", num);
}
}
return 0;
}