P4588 [TJOI2018]数学计算 题解

旅行传送门:https://www.luogu.com.cn/problem/P4588

题目描述

小豆现在有一个数 x,初始值为 1。小豆有 Q 次操作,操作有两种类型:

1 m:将 x 变为 x * m,并输出 x mod M

2 pos:将 x 变为 x 除以第 pos 次操作所乘的数(保证第 pos 次操作一定为类型 1,对于每一个类型 1 的操作至多会被除一次),并输出 x mod M

输入格式

一共有 t 组输入。

对于每一组输入,第一行是两个数字 Q,M

接下来 Q 行,每一行为操作类型 op,操作编号或所乘的数字 m(保证所有的输入都是合法的)。

输出格式

对于每一个操作,输出一行,包含操作执行后的 x mod M 的值。

输入输出样例

输入 #1
1
10 1000000000
1 2
2 1
1 2
1 10
2 3
2 4
1 6
1 7
1 12
2 7
输出 #1
2
1
2
20
10
1
6
42
504
84

说明/提示

对于 20% 的数据,≤ ≤ 500。

对于 100% 的数据,≤ ≤ 10^5,≤ 5,≤ 10^9。

解题思路

第一眼看去,就只对一个数进行操作,这哪是甚么线段树的题,直接上暴力模拟不就完事了(上了就去见祖宗,哪怕开long long也直接亲ma炸穿)(虽然纯当作数论题做也不是不行)。

但转念一想,蓝题不可能这么水,重新审题,题目中有两个操作,一是x乘以一个值,另一个是x除以之前乘过的某个值;乘以一个数又除以一个数,相当于啥也没干,也就可以看成是回溯操作。那么我们不妨以时间为轴建立一棵范围为[1,Q]的线段树,第k个叶子节点的序号表示这是第pos次操作,其存储的值表示x在这次操作中乘以的数。此时第一种操作变为给当前叶节点赋值m,第二种操作变为令第pos个叶节点的值回溯至1,根节点的值就是每次操作执行后x的值。

总的来说是道很有意思的题_(:з」∠)_

AC代码

 1 #include <bits/stdc++.h>
 2 #define FOR(i, j, k) for (int i = (j); i <= (k); i++)
 3 #define MAXQ 100000 + 10
 4 
 5 typedef long long ll;
 6 
 7 ll t, q, mod;
 8 ll tree[MAXQ << 2];
 9 
10 ll read()
11 {
12     ll x = 0, f = 1;
13     char ch = getchar();
14     while (ch < '0' || ch > '9')
15     {
16         if (ch == '-')
17             f = -1;
18         ch = getchar();
19     }
20     while (ch >= '0' && ch <= '9')
21     {
22         x = x * 10 + ch - '0';
23         ch = getchar();
24     }
25     return x * f;
26 }
27 
28 void build(ll k, ll l, ll r)
29 {
30     tree[k] = 1;
31     if (l == r)
32         return;
33     ll mid = (l + r) >> 1;
34     build(k << 1, l, mid);
35     build(k << 1 | 1, mid + 1, r);
36 }
37 
38 void update(ll k, ll l, ll r, ll pos, ll x)
39 {
40     if (l == r)
41     {
42         tree[k] = x;
43         return;
44     }
45     ll mid = (l + r) >> 1;
46     if (pos <= mid)
47         update(k << 1, l, mid, pos, x);
48     else
49         update(k << 1 | 1, mid + 1, r, pos, x);
50     tree[k] = ((tree[k << 1] % mod) * (tree[k << 1 | 1] % mod)) % mod;
51 }
52 
53 int main(int argc, char const *argv[])
54 {
55     t = read();
56     while (t--)
57     {
58         q = read(), mod = read();
59         build(1, 1, q);
60         FOR(i, 1, q)
61         {
62             ll op = read();
63             if (op == 1)
64             {
65                 ll m = read();
66                 update(1, 1, q, i, m);
67                 printf("%lld\n", tree[1] % mod);
68             }
69             else
70             {
71                 ll pos = read();
72                 update(1, 1, q, pos, 1);
73                 printf("%lld\n", tree[1] % mod);
74             }
75         }
76     }
77     return 0;
78 }
View Code

 

posted @ 2021-03-27 16:35  FoXreign  阅读(53)  评论(0编辑  收藏  举报