[BZOJ3813] 奇數國 - 線段樹
阿新 • • 發佈:2018-07-02
歐拉函數 tput return gist pri 乘法 線段 tps number
Submit: 912 Solved: 508
[Submit][Status][Discuss]
第一行一個整數x表示領袖清點和變動存款的總次數。
接下來x行,每行3個整數ai,bi,ci。ai為0時表示該條記錄是清點計劃,領袖會清點bi到ci的銀行存款,你需要對該條記錄計算出GFS想要的答案。ai為1時表示該條記錄是存款變動,你要把銀行bi的存款改為ci,不需要對該記錄進行計算。
013
115
013
117
013
023
24
36
6
explanation
初始化每個國家存款都為3;
1到3的product為27,[1,27]與27不相沖的有18個數;
1的存款變為5;
1到3的product為45,[1,45]與45不相沖的有24個數;
1的存款變為7;
1到3的product為63,[1,63]與63不相沖的有36個數;
2到3的product為9,[1,9]與9不相沖的有6個數。
3813: 奇數國
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 912 Solved: 508
[Submit][Status][Discuss]
Description
在一片美麗的大陸上有100000個國家,記為1到100000。這裏經濟發達,有數不盡的賬房,並且每個國家有一個銀行。某大公司的領袖在這100000個銀行開戶時都存了3大洋,他惜財如命,因此會不時地派小弟GFS清點一些銀行的存款或者讓GFS改變某個銀行的存款。該村子在財產上的求和運算等同於我們的乘法運算,也就是說領袖開戶時的存款總和為3100000。這裏發行的軟妹面額是最小的60個素數(p1=2,p2=3,…,p60=281),任何人的財產都只能由這60個基本面額表示,即設某個人的財產為fortune(正整數),則fortune=p1^k1*p2^k2*......p60^K60。 領袖習慣將一段編號連續的銀行裏的存款拿到一個賬房去清點,為了避免GFS串通賬房叛變,所以他不會每次都選擇同一個賬房。GFS跟隨領袖多年已經摸清了門路,知道領袖選擇賬房的方式。如果領袖選擇清點編號在[a,b]內的銀行財產,他會先對[a,b]的財產求和(計為product),然後在編號屬於[1,product]的賬房中選擇一個去清點存款,檢驗自己計算是否正確同時也檢驗賬房與GFS是否有勾結。GFS發現如果某個賬房的編號number與product相沖,領袖絕對不會選擇這個賬房。怎樣才算與product不相沖呢?若存在整數x,y使得number*x+product*y=1,那麽我們稱number與product不相沖,即該賬房有可能被領袖相中。當領袖又賺大錢了的時候,他會在某個銀行改變存款,這樣一來相同區間的銀行在不同的時候算出來的product可能是不一樣的,而且領袖不會在某個銀行的存款總數超過1000000。 現在GFS預先知道了領袖的清點存款與變動存款的計劃,想請你告訴他,每次清點存款時領袖有多少個賬房可以供他選擇,當然這個值可能非常大,GFS只想知道對19961993取模後的答案。Input
Output
輸出若幹行,每行一個數,表示那些年的答案。Sample Input
6013
115
013
117
013
023
Sample Output
1824
36
6
explanation
初始化每個國家存款都為3;
1到3的product為27,[1,27]與27不相沖的有18個數;
1的存款變為5;
1到3的product為45,[1,45]與45不相沖的有24個數;
1的存款變為7;
1到3的product為63,[1,63]與63不相沖的有36個數;
2到3的product為9,[1,9]與9不相沖的有6個數。
HINT
x≤100000,當ai=0時0≤ci−bi≤100000
題解:
用線段樹維護區間乘積,並且用一個longlong類型變量表示這個區間有沒有選擇某一個質數;
合並的時候乘積就直接乘起來, 狀態直接把左兒子右兒子的狀態取或;
計算的時候直接按照歐拉函數的數學公式算
Code:
#include <iostream> #include <cstdio> #include <bitset> #include <algorithm> using namespace std; #define ll long long #define mod 19961993 int TI; int ps[66] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281}; int inv[300]; struct Segment { ll sum; ll bit; Segment() {sum = 1, bit = 0;} }t[400009], ans; #define ls(o) o << 1 #define rs(o) o << 1 | 1 #define sum(o) t[o].sum #define bit(o) t[o].bit inline void update(int o){sum(o)=sum(ls(o))*sum(rs(o))%mod;bit(o)=(bit(ls(o))|bit(rs(o)));} inline void build(int o, int l, int r) { if (l == r) { sum(o) = 3; bit(o) = 2; return ; } int mid = l + r >> 1; build(o<<1, l, mid); build(o<<1|1, mid + 1, r); sum(o)=sum(ls(o))*sum(rs(o))%mod; bit(o) = 2; } inline void change(int l,int r, int o, int now, int der) { if (l == r) { sum(now) = der; ll p = 0; for (register int i = 1 ; i <= 60 ; i ++) if (der % ps[i] == 0) p |= 1LL<<(i-1); bit(now) = p; return ; } int mid = l + r >> 1; if (o <= mid) change(l, mid, o, ls(now), der); else change(mid + 1, r, o, rs(now), der); sum(now) = sum(ls(now)) * sum(rs(now)) % mod; bit(now) = bit(ls(now)) | bit(rs(now)); } inline void query(int l, int r, int lq, int rq, int o) { if (l >= lq and r <= rq) { ans.sum = (ans.sum * sum(o)) % mod; ans.bit |= bit(o); return; } int mid = l + r >> 1; if (lq <= mid) query(l, mid, lq, rq, ls(o)); if (rq > mid) query(mid + 1, r, lq, rq, rs(o)); } int main() { scanf("%d", &TI); inv[1] = 1; for (register int i = 2 ; i <= 281 ; i ++) inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod; int n = 100000; build(1, 1, n); for (register int i = 1 ; i <= TI ; i ++) { int opt, x, y; scanf("%1d%1d%1d", &opt, &x, &y); if (opt == 0) { ans.sum = 1, ans.bit = 0; query(1, n, x, y, 1); ll res = ans.sum; for (register int j = 1 ; j <= 60 ; j ++) { if (ans.bit & (1LL<<(j-1))) { res = (res * (ps[j] - 1)) % mod; res = (res * inv[ps[j]]) % mod; } } printf("%d\n", (int)res); } else { change(1, n, x, 1, y); } } return 0; }
[BZOJ3813] 奇數國 - 線段樹