[luogu P5325][模板]Min_25篩

Address

Luogu #5325

Solution

  • pip_i 表示第 ii 小的質數(p[0]=1p[0]=1),s1[x]=i=1xp[x]s2[x]=i=1xp[x]2s1[x]=\sum_{i=1}^{x}p[x],s2[x]=\sum_{i=1}^{x}p[x]^2
  • g1(x,i)g1(x,i) 爲:j=1x[jjpi]j\sum_{j=1}^{x}[j是質數或j的最小質因子大於p_i]j
  • g2(x,i)g2(x,i) 爲:j=1x[jjpi]j2\sum_{j=1}^{x}[j是質數或j的最小質因子大於p_i]j^2
  • 因爲 nn 以內的合數的最小質因子爲 O(n)O(\sqrt n),所以第二維的 ii 滿足:pi2np_i^2≤n
  • s(x,y)s(x,y) 爲:j=1x[jpy]j2j\sum_{j=1}^{x}[j的最小質因子大於p_y]j^2-j
  • 那麼顯然有: ans=S(x,y)+1ans=S(x,y)+1
  • 假設我們已經求得了所有的 g1(x,i),g2(x,i)g1(x,i),g2(x,i)
  • 考慮如何求 s(x,y)s(x,y)
  • 我們分別考慮質數與合數對答案的貢獻。
  • 對於質數,記 n\sqrt n 以內的質數個數爲 cc,我們要求的就是:res=j=y+1cpj2pjres=\sum_{j=y+1}^{c}p_j^2-p_j
  • 我們把它轉換爲兩個前綴和相減的形式(前 cc 個的貢獻 -jj 個的貢獻),並且利用上 g1g2g1,g2,那麼有:res=g2(x,c)g1(x,c)(s2[y]s1[y])res=g2(x,c)-g1(x,c)-(s2[y]-s1[y])
  • 對於合數,有最小質因子大於 pyp_y 的限制。
  • 我們枚舉 i,ji,j,並計算所有滿足以下條件的合數 aa 對答案的貢獻:
    1.aa 的最小質因子爲 pip_i
    2.aa 可以分解出 jjpip_i
  • 我們把每個合法的 aa 都分解出因數 pijp_i^j,記 bb 爲分解後的 aa,那麼 bb 要滿足條件:
    1.bb 的最小質因子大於 pip_i b=1b=1
    2.bxpijb≤\lfloor\frac{x}{p_i^j}\rfloor
  • 那麼我們就得出了遞推式:s(x,y)=resi=y+1cj=1,pijxf(pij)(s(xpij,i)+[j=1])s(x,y)=res-\sum_{i=y+1}^{c}\sum_{j=1,p_i^j≤x}f(p_i^j)*(s(\lfloor\frac{x}{p_i^j}\rfloor,i)+[j=1])
  • 現在還有一個問題,就是求 g1,g2g1,g2
  • 我們可以這樣求 g1g1g2g2 同理):
  • 先讓 g1(x,i)=g1(x,i1)g1(x,i)=g1(x,i-1),接着要減去所有滿足最小質因子等於 pip_i合數的貢獻。
  • 我們還是把這些合數分解出因數 pip_i,然後分解後的數 dd 要滿足以下條件:
    1.dd 的最小質因子大於 pi1p_{i-1}
    2.dxpid≤\lfloor\frac{x}{p_i}\rfloor
  • 顯然有:g1(x,i)=g1(x,i1)pi(g1(xpi,i1)s1[i1])g1(x,i)=g1(x,i-1)-p_i(g1(\lfloor\frac{x}{p_i}\rfloor,i-1)-s1[i-1])
  • 然後還有一個問題就是 g1,g2,sg1,g2,s 的第一維可能到 O(n)O(n) 級別,需要離散化。
  • 顯然第一維只可能是某個 ni\lfloor\frac{n}{i}\rfloor 的值。
  • 那麼當 xnx≤\sqrt n時,記 id1[x]id1[x] 表示 xx 離散化後的值。
  • 否則,記 id2[n/x]id2[n/x] 表示 xx 離散化後的值。

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

const int e = 1e6 + 5, mod = 1e9 + 7;
ll g1[e], g2[e], n, s1[e], s2[e], a[e];
bool bo[e];
int cnt, p[e], tot, id1[e], id2[e], s, inv6;

inline int plu(int x, int y)
{
	(x += y) >= mod && (x -= mod);
	return x;
}

inline int sub(int x, int y)
{
	(x -= y) < 0 && (x += mod);
	return x;
}

inline int ksm(int x, int y)
{
	int res = 1;
	while (y)
	{
		if (y & 1) res = (ll)res * x % mod;
		y >>= 1;
		x = (ll)x * x % mod;
	}
	return res;
}

inline int calc1(ll x)
{
	x %= mod;
	return (ll)x * (x + 1) / 2 % mod;
}

inline int calc2(ll x)
{
	x %= mod;
	return (ll)x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod;
}

inline void init()
{
	inv6 = ksm(6, mod - 2); s = sqrt(n);
	ll i, j;
	for (i = 1; i <= n; i = j + 1)
	{
		a[++tot] = n / i;
		j = n / a[tot];
		g1[tot] = sub(calc1(a[tot]), 1);
		g2[tot] = sub(calc2(a[tot]), 1);
		if (a[tot] <= s) id1[a[tot]] = tot;
		else id2[n / a[tot]] = tot;
	}
}

inline void sieve()
{
	int i, j;
	for (i = 2; i <= s; i++)
	{
		if (!bo[i])
		{
			p[++cnt] = i;
			s1[cnt] = plu(s1[cnt - 1], i);
			s2[cnt] = plu(s2[cnt - 1], (ll)i * i % mod);
		}
		for (j = 1; j <= cnt && i * p[j] <= s; j++)
		{
			bo[i * p[j]] = 1;
			if (i % p[j] == 0) break;
		}
	}
}

inline void solve_g()
{
	int i, j;
	for (i = 1; i <= cnt; i++)
	{
		for (j = 1; j <= tot; j++)
		if ((ll)p[i] * p[i] <= a[j])
		{
			ll x = a[j], y = x / p[i];
			int k = y <= s ? id1[y] : id2[n / y], z = x <= s ? id1[x] : id2[n / x];
			g1[z] = sub(g1[z], (ll)p[i] * sub(g1[k], s1[i - 1]) % mod);
			g2[z] = sub(g2[z], (ll)p[i] * p[i] % mod * sub(g2[k], s2[i - 1]) % mod);
		}
	}
}

inline int dfs(ll x, int y)
{
	if (p[y] >= x) return 0;
	int i, j, k = x <= s ? id1[x] : id2[n / x];
	int res = sub(sub(g2[k], g1[k]), sub(s2[y], s1[y]));
	ll pj;
	for (i = y + 1; i <= cnt && (ll)p[i] * p[i] <= x; i++)
	for (j = 1, pj = p[i]; pj <= x; j++, pj = pj * p[i])
	{
		int f = pj % mod;
		f = (ll)f * sub(f, 1) % mod;
		res = plu(res, (ll)f * plu(dfs(x / pj, i), j != 1) % mod);
	}
	return res;
}

int main()
{
	cin >> n; init(); sieve(); solve_g();
	cout << plu(dfs(n, 0), 1) << endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章