P4588 TJOI2018 數學計算 題解

2022-09-15 01:48:13 字數 1872 閱讀 6870

旅行傳送門:

小豆現在有乙個數 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 22 1

1 21 10

2 32 4

1 61 7

1 12

2 7

輸出 #1複製

212

201016

42504

84

對於 20% 的資料,1 ≤ q ≤ 500。

對於 100% 的資料,1 ≤ q ≤ 10^5,t ≤ 5,m ≤ 10^9。

第一眼看去,就只對乙個數進行操作,這哪是甚麼線段樹的題,直接上暴力模擬不就完事了(上了就去見祖宗,哪怕開long long也直接親ma炸穿)(雖然純當作數論題做也不是不行)。

但轉念一想,藍題不可能這麼水,重新審題,題目中有兩個操作,一是x乘以乙個值,另乙個是x除以之前乘過的某個值;乘以乙個數又除以乙個數,相當於啥也沒乾,也就可以看成是回溯操作。那麼我們不妨以時間為軸建立一棵範圍為[1,q]的線段樹,第k個葉子節點的序號表示這是第pos次操作,其儲存的值表示x在這次操作中乘以的數。此時第一種操作變為給當前葉節點賦值m,第二種操作變為令第pos個葉節點的值回溯至1,根節點的值就是每次操作執行後x的值。

總的來說是道很有意思的題_(:з」∠)_

1 #include 2

#define for(i, j, k) for (int i = (j); i <= (k); i++)

3#define maxq 100000 + 10

45 typedef long

long

ll;6

7ll t, q, mod;

8 ll tree[maxq << 2];9

10ll read()

1120

while (ch >= '

0' && ch <= '9'

)2125return x *f;26}

2728

void

build(ll k, ll l, ll r)

2937

38void

update(ll k, ll l, ll r, ll pos, ll x)

3945 ll mid = (l + r) >> 1;46

if (pos <=mid)

47 update(k << 1

, l, mid, pos, x);

48else

49 update(k << 1 | 1, mid + 1

, r, pos, x);

50 tree[k] = ((tree[k << 1] % mod) * (tree[k << 1 | 1] % mod)) %mod;51}

5253

int main(int argc, char

const *ar**)

5469

else

7075}76

}77return0;

78 }

view code

P4588 TJOI2018 數學計算

說實話第一眼沒看出來這是個線段樹題 仔細一想就算是你把每次操作計算出來,每次除去找數,然後除掉,那樣就只能最 後取mod,或求很多逆元,不取模你會炸 longlong。如何解決?我們以時間為軸,建立線段樹,葉子結點維護該操作時間的乘數,非葉子結點維護 區間乘,葉子結點一開始都為 1 然後每次乘,進行...

線段樹 P4588 TJOI2018 數學計算

這道題目,看起來只給了乙個數,與線段樹關係不大,但是將每次的操作存起來,就相當於是點更新,段查詢 乘積 這樣就可以轉化為線段樹的問題了。對於操作1,我們可以把對應的位置修改為相應值 操作2,把當前位置,和pos的位置改為1 並維護線段樹即可 includeusing namespace std co...

洛谷 P4588 TJOI2018 數學計算

小豆現在有乙個數x xx,初始值為1 11.小豆有q qq次操作,操作有兩種型別 一共有t tt組輸入 t 5 t leq 5 t 5 對於每一組輸入,第一行是兩個數字q,m od q 100000,m od 1000000000 q,mod q leq 100000,mod leq 1000000...