日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Min_25筛学习Tip+链接

發(fā)布時間:2024/4/11 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Min_25筛学习Tip+链接 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

機房里差不多都會Min_25篩了,我也趕緊補一波坑v_v
參考:
txc的Min_25篩學習筆記
yx的Min_25篩學習筆記
由于前面兩位dalao的標題都是筆記,所以我這里就是小記了,因為這里只記錄我的一些思考,并不全面
我也看了2018的論文集,那里的說明比較規(guī)范

什么是Min_25篩

我聽yx說只要是多項式都能用Min_25篩前綴和

實際上,存在一種實現(xiàn)難度更低,同時在較小的數據范圍下表現(xiàn)更好的方法,它和洲閣篩的思想類似,但理解起來更為容易
——朱震霆, 《一些特殊的數論函數求和問題》, 國家集訓隊2018論文集。

聽說能代替洲閣篩,所以還不會洲閣篩的我趕緊來學一波操作
在不考慮常數,只考慮復雜度的情況下,Min_25篩是比杜教篩快的,Min_25的復雜度是Θ(n34logn)\Theta(\frac{n^{\frac34}}{log\ n })Θ(log?nn43??)的,而杜教篩的復雜度是Θ(n23)\Theta(n^{\frac23})Θ(n32?),使用Mathematica計算可以發(fā)現(xiàn),當nnn的值滿足2.08977&lt;n&lt;3.00405?10222.08977&lt;n&lt;3.00405*10^{22}2.08977<n<3.00405?1022的時候,Min_25篩的復雜度是更優(yōu)的,下界…不用管,上界的話如果nnn到了這個級別按這兩個復雜度已經做不了了(別想著打表,跑出這樣的數據可能要跑100+天,再說空間復雜度也受不了),所以Min_25篩的效率還是非常優(yōu)越的
Min_25篩空間復雜度Θ(n)\Theta(\sqrt n)Θ(n?)
再考慮適用范圍:
杜教篩限制重重,需要更麻煩的推式子,而看Min_25適用的范圍的介紹:

如果一個積性函數 f(i)在 i是質數時是一個關于 i的低次多項式,并且在質數的冪處的能快速求,那么大概可以用Min_25篩來求
——txc

相比之下,Min_25篩無疑是適用范圍較廣的
(yx:現(xiàn)在又找到杜教篩能做的而Min_25篩不能做的題嗎,如果有歡迎評論)

知識儲備

  • 數論相關的基礎知識(如果不太了解可以參考我的博客數論學習)

正文

咕咕咕咕咕
咕咕咕咕咕
等博主學完Min_25篩后,發(fā)現(xiàn)別人已經寫的比較清楚了,我會在后面給出一些補充,在這些補充下,就能學完Min_25篩
博主覺得自己在寫一遍沒有什么意義

學習指南 (生存指南)

  • step1 打開zzt的論文
    作為一名OIer你想必應該知道在哪里有論文,這里就不提供鏈接了(其實是因為實在不知道如何上傳,如果有需要可以聯(lián)系我,左邊那一欄有聯(lián)系方式)
    zzt的論述還是很嚴密的,在思路上能給你很大的啟發(fā),認真看
  • step2 打開txc的Min_25篩學習筆記
    這一篇博客的思路是和zzq一樣的,但是描述更加通俗,并且步驟更加簡潔(沒有冗長的式子)看完你應該能懂Min_25的更具體的原理與實現(xiàn)
    注意:txc的博客中的一些定義回合zzt的論文中的定義不同,請仔細看,并且,對于第二部分,zzt的做法對應txc的第二種實現(xiàn)方式(似乎第二種方式常數小,但受到一些局限)
  • step3 看我寫的內容
    我是按這個步驟做下來的,由于我水平有限,所以看懂了式子后不知道怎么實現(xiàn)+不清楚復雜度,而看代碼是沒那么容易就清楚做法的,所以,在這里我會給一些Tip:
    Tip 1:
    在txc的博客中,他所說的“第一部分”的最后所說的記錄n\sqrt nn?個值指的是記錄當前已經求好的g(?,b?1)g(*,b-1)g(?,b?1),現(xiàn)在要求的是g(?,b)g(*,b)g(?,b)
    容易發(fā)現(xiàn),我們這里的bbb的最大值是222n\sqrt nn?的質數數量,所以總的bbb的取值是Θ(nlnn)\Theta(\frac {\sqrt n}{ln\ {\sqrt n}})Θ(ln?n?n??)的,這個值是可以接受的
    考慮每一次轉移,txc的博客里寫到了a&lt;prime2a&lt;prime^2a<prime2的都是不用轉移的
    剩下的就從最后一個值向前枚舉更新,由于轉移只會用到前面的值,所以只用開一個數組就夠了,由于aaa的取值是?nm?\left\lfloor\frac nm \right\rfloor?mn??形式的,所以只用Θ(n)\Theta(\sqrt n)Θ(n?)種,空間是Θ(n)\Theta(\sqrt n)Θ(n?)
    Tip 2:
    在寫代碼的時候有很多可以優(yōu)化常數的地方,這個時候就要看仔細了,只有獲取合適的寫法才能讓算法既好寫又跑的快,并且對于Min_25篩,要注意哪些地方要用long long哪些地方不用,這是很容易錯的(我自己就WA了好多發(fā))
  • step4 自己寫一遍Min_25篩,并做相關的習題
    這里采用一道例題,BZOJ3944 Sum
    這道題其實也是杜教篩模板題,這里用Min_25篩的板子也不錯
    貼出代碼
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #include<cmath> namespace fast_IO {const int IN_LEN=10000000,OUT_LEN=10000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);} } using namespace fast_IO; #define getchar() getchar_() #define putchar(x) putchar_((x)) #define rg register typedef long long LL; template <typename T> inline T max(const T a,const T b){return a>b?a:b;} template <typename T> inline T min(const T a,const T b){return a<b?a:b;} template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;} template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;} template <typename T> inline T abs(const T a){return a>0?a:-a;} template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;} template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);} template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;} template <typename T> inline T square(const T x){return x*x;}; template <typename T> inline void read(T&x) {char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x; } template <typename T> inline void printe(const T x) {if(x>=10)printe(x/10);putchar(x%10+'0'); } template <typename T> inline void print(const T x) {if(x<0)putchar('-'),printe(-x);else printe(x); } LL sum1[700001]; int T,n,part,tot,qz[700001],prime[700001],sq[700001],primesize,sum0[700001],id[700001]; inline int ck(const int x){return x<=part?x:tot-n/x+1;} int calc_mu(const int a,const int b) {if(a<prime[b])return 0;int ans=sum0[ck(a)]+b-1;for(rg int i=b;i<=primesize&&sq[i]<=a;i++)ans-=calc_mu(a/prime[i],i+1);return ans; } LL calc_phi(const int a,const int b) {if(a<prime[b])return 0;LL ans=sum1[ck(a)]-(qz[b-1]-(b-1));for(rg int i=b;i<=primesize&&sq[i]<=a;i++){ans+=(calc_phi(a/prime[i], i+1)+prime[i])*(prime[i]-1);for(rg int x=prime[i]*prime[i],mine=x-prime[i];(LL)x*prime[i]<=a;x*=prime[i],mine*=prime[i])ans+=(calc_phi(a/x, i+1)+prime[i])*mine;}return ans; } int main() {read(T);while(T--){read(n);if(!n){print(0),putchar(' '),print(0),putchar('\n');continue;}part=sqrt(n);tot=primesize=0;for(rg int i=1;i<=part;i++)id[++tot]=i,sum0[tot]=i-1,sum1[tot]=((((LL)i+1)*i)>>1)-1;id[++tot]=n/part;if(id[tot]!=part)sum0[tot]=id[tot]-1,sum1[tot]=((LL)(((LL)id[tot]+1)*id[tot])>>1)-1;else tot--;for(rg int i=part-1;i>=1;i--)id[++tot]=n/i,sum0[tot]=id[tot]-1,sum1[tot]=((((LL)id[tot]+1)*id[tot])>>1)-1;for(rg int i=2;i<=part;i++)if(sum0[i]!=sum0[i-1]){ const int limit=(LL)i*i;for(rg int j=tot;id[j]>=limit;j--){const int t=ck(id[j]/i);sum1[j]-=(sum1[t]-qz[primesize])*i;sum0[j]-=sum0[t]-primesize;}prime[++primesize]=i,sq[primesize]=i*i,qz[primesize]=qz[primesize-1]+i;}for(rg int i=1;i<=tot;i++)sum1[i]-=sum0[i],sum0[i]=-sum0[i];//sum1為phi的前綴和,sum0為mu的前綴和print(calc_phi(n,1)+1),putchar(' '),print(calc_mu(n,1)+1),putchar('\n');}return flush(),0; }

總結

Min_25篩本身代碼并沒有很長,我認為關鍵在于寫對(因為對于不同的函數寫法不一樣)。如果熟練掌握了Min_25篩,還是能簡化不少問題的

總結

以上是生活随笔為你收集整理的Min_25筛学习Tip+链接的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。