AtCoder ABC298 D - Writing a Numeral
题目描述
我们有一个数字串 1。
执行
1 x将x 插入S 最后;2删除S 的第一个数字;3输出当前的S 。
数据范围
分析
对于这道题目,我们当然不可以按照题目要求模拟,定义一个字符串 S.push_back(x),第二个操作直接 S.erase(s.begin()),第三个操作直接计算。
这样显然不可取,对于第二个和第三个操作都是
观察第一个和第二个操作,在末尾插入,在开头删除,正好是队列 FIFO 的性质。
接下来考虑队列 queue,以下为三种操作对应的实现过程:
- 在末尾插入
x ,可以q.push(x); - 删除第一个元素,也就是弹出队头元素,可以
q.pop(); - 输出当前的数字,可以在上面两个操作中顺带地求出
res ,输出即可。
代码
#include <iostream>
#include <cmath>
#include <queue>
using namespace std;
#define int long long
const int N = 1e6 + 10, P = 998244353;
int Q, op, x, res = 1;
queue<int> q; // 队列
int add(int a, int b) // (a + b) % P 的值
{
return ((a % P) + (b % P) % P + P) % P;
}
int mul(int a, int b) // (a ×b) % P 的值
{
return ((a % P) * (b % P)) % P;
}
int fpm(int a, int b) // (a ^ b) % P 的值
{
int res = 1;
while (b)
{
if (b & 1) res = mul(res, a);
b >>= 1;
a = mul(a, a);
}
return res;
}
signed main()
{
q.push(1); // 开始队列中为 1
cin >> Q;
while (Q -- ) // Q 次询问
{
cin >> op;
if (op == 1) // 第一种操作:将 x 入队
{
cin >> x;
q.push(x);
res = add(res * 10, x);
}
if (op == 2) // 第二种操作:弹出队头元素
{
res = add(res, -(q.front() * fpm(10, q.size() - 1)));
q.pop();
}
if (op == 3) // 第三种操作:输出答案
{
cout << res << '\n';
}
}
return 0;
}