codeforces 1114F 線段樹練習

2022-07-23 18:09:19 字數 3286 閱讀 4593

這是一道用線段樹維區間值的一道題,,題意很簡單,,就是對於給定的乙個序列,,初始時每個數的值不大於300,,,然後有兩中操作,,乙個是對區間[l, r]的每個數乘上以個數x,,乙個是詢問區間的乘積的尤拉函式值,,,

首先對於第乙個操作顯然可以用線段樹的延遲更新來完成,,

對於第二個操作,,我最先沒考慮資料,,就想著直接維護區間的乘積,,對最後的區間乘積求尤拉函式值,,,但是,,,即使資料初始值很小,,但是多次累乘x後會爆ll,甚至是ull,,,

正解是這樣的:

對於第乙個操作,,每次都儲存區間模mod的乘積,,,

對於第二個操作,,因為我們是求的區間積的尤拉函式值,也就是

\(mul_ \times phi(mul_) = mul_ \times \prod_^j \)

\(prime[i] 是指 mul_ 的質因數\)

因為直接存 \(mul_\) 會爆掉,,而最後的結果實在mod下的數,,300以里的質數也只有62個,,所以可以標記出乘積的所有質因數,,用乙個ll的數就行了(狀壓的思想),,對於任意乙個區間的乘積的標記都可以用兩個子節點的標記值的或運算得到,,同時標記值也只會因為乘上的那個數x而增加,,,公式裡的除 \(prime[i]\) 也可以用逆元搞定,,這樣這個操作就弄出來了,,

一開始我自己寫爆了之後,就照著別人的思路一點一點的改,,莫名其妙的t,,一直以為是線段樹寫醜了,,,,後來看到乙個人寫的很簡單但也過了,,,自己就重寫了一遍過了,,數論+線段樹的題第一次寫,,學到很多,,尤其是狀壓的思想,,逆元,還有線段樹作為乙個維護的工具的使用,,,兩個引數的返回可以使用pairpii型來返回,,

#include //#include //#include //#include //#include #define aaa cout<<233const int inf = 0x3f3f3f3f;//1061109567

const ll linf = 0x3f3f3f3f3f3f3f;

const double eps = 1e-6;

const double pi = 3.14159265358979;

const int maxn = 4e5 + 5; //注意資料範圍,,,因為這個wa了一發,,,,(為啥不是re233)

const int maxm = 2e5 + 5;

const ll mod = 1e9 + 7;

inline int read() //快讀

inline ll pow_(ll a, ll b, ll p) //快速冪

return ret;

}//find all prime from 1 to 300

bool isprime[305];

int prime[70], tot = -1;

int inv_prime[70];

void init() //尋找300以內的質數及其質數的逆元

}}ll find_prime(ll x) //尋找數x的質因數,存在則對應質數陣列的index位位1,這樣最後返回的值的二進位制表示即為狀壓標記的結果

ll mull(ll a, ll b) //帶模的乘法

ll mul[maxn << 2], vis[maxn << 2], laz1[maxn << 2], laz2[maxn << 2];

int a[maxn];

#define mid ((l+r)>>1)

#define lc (rt<<1)

#define rc (rt<<1|1)

void pushup(int rt)

void pushdown(int rt, int llen, int rlen)

inline void build(int rt, int l, int r)

build(lc, l, mid);

build(rc, mid + 1, r);

pushup(rt);

return;

}inline void update(int rt, int l, int r, int l, int r, int x, ll vx)

if(laz1[rt] > 1)pushdown(rt, mid - l + 1, r - mid);

if(laz2[rt])pushdown(rt, mid - l + 1, r - mid);

if(r <= mid)update(lc, l, mid, l, r, x, vx);

else if(l > mid)update(rc, mid+1, r, l, r, x, vx);

else update(lc, l, mid, l, r, x, vx), update(rc, mid+1, r, l, r, x, vx);

// if(l <= mid)update(lc, l, mid, l, r, x, vx);

// if(r > mid)update(rc, mid + 1, r, l, r, x, vx);

pushup(rt);

return;

}inline pii query(int rt, int l, int r, int l, int r)//詢問區間的乘積值和標記值

if(laz1[rt] > 1)pushdown(rt, mid - l + 1, r - mid);//乘積的懶惰標記大於一說明待更新區間

if(laz2[rt])pushdown(rt, mid - l + 1, r - mid); //標記的懶惰值非零說明待更新

if(r <= mid)return query(lc, l, mid, l, r); //詢問區間再左子區間時,,遞迴詢問左子區間

if(l > mid)return query(rc, mid + 1, r, l, r);

pii a = query(lc, l, mid, l, r); //a為佐子區間的值

pii b = query(rc, mid + 1, r, l, r); //b為侑子區間的值

return pii(mull(a.first, b.first), (a.second | b.second));//總區間的值為左右子區間的乘積的積和標記的或

}ll phi(ll mul, ull vis) //利用標記指求其尤拉函式值

int main()

else

}return 0;

}

看來只做簡單題是學不到新東西的,,,難題雖然難,,熬夜弄了兩天wa了好幾發但最後弄出來還是很有意義的,,,

同時多看看別人的**也很有感觸,,學到很多好東西,,

(end)

Codeforces 1114C 數論 唯一分解

解題思路 y1s1,拿到這題我腦袋中只有暴力,觀摩了別人的部落格,學到了點東西。對於本題,我們可以知道,在b進製後有幾個0表示的是這個數是b的幾次方的倍數,於是題目便轉化為了求n的階乘最大能被b的幾次方整除,從唯一分解定理我們可以知道,我們對n的階乘和b唯一分解得到 b p1 times p2 ti...

codeforces 1194F 組合數學

傳送門 你有n個事件,你需要按照1 n的順序完成這些事件,每個事件需要 t i 的時間完成,你現在一共有t的時間去做這些事情,每做一件事情的時候,你有0.5的概率花費 t i 的時間完成他,也有0.5的概率花費 t i 1 的時間去完成他,如果在做這個事件的時候時間花完了,你就相當於沒有做成這個事件...

Codeforces 985F 字串雜湊

題目鏈結 題意簡述 給定乙個長度為n n 2e5 的字串s 僅含有小寫字母 有m m 2e5 次查詢。每次查詢給三個數,x,y,len,求在s x s x len 1 和s y s y len 1 是否存在相應位置唯一對應關係。例如aba和brb,aaa和kkk,abs和ert是唯一對應。aab和a...