LOJ 6202 葉氏篩法 min 25 篩

2022-05-07 18:57:09 字數 3700 閱讀 9517

求 \([l, r]\) 之間的素數之和 . \(l≤10^,2×10^ \le r \le 10^\)

乙個有點裸的min_25篩? 現在我只會篩素數的字首和 , 合數的過幾天再學吧 .

首先推薦一波yyb大佬部落格這個人很強 , 別那麼fake就好啦

令 \(f(x) = x\) 顯然此處 \(f(x)\) 是完全積性函式 .

我們需要求的就是 $$\displaystyle \sum_^ [i \in prime] f(i)$$ .

這個就是min_25篩的預處理部分啦.

由 yyb部落格 可得 .

對於下面這個表示式 ,

\[\displaystyle g(n,j)=\sum_^ni[i\in p\ or \min(p)>p_j,p|i,p\in p\ ]

\]有如下乙個遞推式 :

\[g(n,j)=\begin g(n,j-1)&p_j^2\gt n\\ g(n,j-1)-p_[g(\frac,j-1)-g(p_j-1,j-1)]&p_j^2\le n\end

\]這個直接實現是 \(\displaystyle o(\frac}})\) 的複雜度 qwq

然後考慮**實現 .

首先預處理前 \(\sqrt n\) 的素數 , (假設處理到了 \(lim\) )

以及 \(i=1 \sim lim\) 的 \(f(x)\) 字首和 . (此處可適當處理多一點 , 時間效率會提高)

然後假設我們當前考慮的是 \(g(n, m)\) .

直觀上共有三步 .

\(p_^2 > n\) 且 \(n \le lim\) , 那麼此時可以直接用之前預處理的答案 , 因為此時存在有貢獻的數隻可能為素數 .

將 \(m\) 一直縮小到 \(n < p_m^2\) . 這個利用了遞推式 \(p_j^2 > n\) 時 \(g(n,j) = g(n, j - 1)\) 的那個定理 .

然後不斷將 \(m\) 下降, 直至下降到 \(0\) , 此間需要要遞迴計算 \(p_[g(\frac,j-1)+g(p_j-1,j-1)]\) 的值 , 其中後者 \(g(p_j-1,j-1)\) 可以用前面預處理 , 遞迴下去也只會有一層 . 而前者會不斷遞迴計算 . 其中 \(m\) 到 \(0\) 的時候 , 就是邊界情況 : \(\displaystyle g(n, 0)=\sum_^ i\) . 這個是很顯然的 , 因為此時所有數都計入了貢獻 , 但 \(1\) 是無法給予這個貢獻的 . (一開始此處除錯許久... )

直接按前面的式子模擬即可。

#include #define for(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)

#define fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)

#define set(a, v) memset(a, v, sizeof(a))

#define debug(x) cout << #x << ':' << x << endl

using namespace std;

void file()

const int n = 1e7 + 1e3, lim = 1e7;

typedef __int128 ll;

inline ll read()

inline void out(ll x, bool fir = true) out(x / 10, false); putchar (x % 10 + 48); if (fir) putchar ('\n');

}int prime[n], cnt = 0; bitsetis_prime;

ll sump[n];

void init(int maxn) }}

inline ll sum(ll x)

int tot = 0;

ll sump(ll n, int m)

inline ll calc(ll x)

int main ()

如何做非遞迴呢?

考慮每次的 \(j\) 都是不斷減小的,就是我們會依次會除掉乙個個質因子 \(p_j\) 。

我們從小到大列舉每個質因子 \(p_j \le \lfloor \sqrt n \rfloor\) ,然後再從小到大列舉每個 \(n\) 的塊 \(\displaystyle \lfloor \frac \rfloor\) (只有 \(\sqrt n\) 個)。

然後利用上面的式子直接遞推即可。

具體實現的時候由於只有 \(\sqrt n\) 個,我們對於 \(\le \sqrt n\) 的和 \(> \sqrt n\) 的進行分塊即可。

#include #define for(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)

#define fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)

#define rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)

#define set(a, v) memset(a, v, sizeof(a))

#define cpy(a, b) memcpy(a, b, sizeof(a))

#define debug(x) cout << #x << ": " << (x) << endl

using namespace std;

//typedef long long ll;

typedef __int128 ll;

templateinline bool chkmin(t &a, t b)

templateinline bool chkmax(t &a, t b)

inline ll read()

inline void out(ll x)

char stk[25]; int top = 0;

for (; x; x /= 10) stk[++ top] = (x % 10) + 48;

while (top) putchar (stk[top --]); putchar ('\n');

}void file()

const int n = sqrt(1e11) * 2 + 10;

bitsetis_prime;

int prime[n / 10], pcnt; ll sump[n / 10];

void linear_sieve(int maxn)

for (int j = 1; j <= pcnt && 1ll * prime[j] * i <= maxn; ++ j) }}

int d, id1[n], id2[n];

ll val[n], res[n];

#define id(x) (x <= d ? id1[x] : id2[n / (x)])

inline ll sum(ll n)

ll min25_sieve(ll n)

int main ()

總結 篩法 Min 25篩

對於積性函式f x f x f x 求 i 1i n f i 其中n 1011 左右 sum f i 其中n leq 10 左右 i 1 i n f i 其 中n 1 011左 右 必須滿足的條件是 當p為質數時,f p f p f p 必須能表示為乙個多項式的形式,即f p a0 a1p a2p ...

與擴充套件埃氏篩(min 25篩?)玩耍

這篇部落格是一年前寫的 那時這東西好像還是個cai佬偷偷教我們的黑科技但現在似乎已經人盡皆知了 cai佬說這東西叫做擴充套件埃氏篩,但似乎它和min25篩是乙個東西?例題 loj6235 區間素數個數 設sum x sum x sum x 表示小於等於x的素數個數。假設我很蠢 這件事根本不用假設好嗎...

LOJ6682 夢中的數論(min 25篩)

首先題目裡面的式子乍一看很扯,實際上我們發現對於i ii,它的每一對約數都出現了一次並且被計算,則實際上我們要求的是 ans i 1n d i 2 12 i 1nd2 i i 1 nd i ans sum n frac sum nd 2 i sum nd i ans i 1 n 2d i 21 i ...