【UOJ188】 Sanrd【類min_25篩】

題意:設f(i)f(i)表示ii的不嚴格次大質因子(沒有爲00),求i=lrf(i)\sum_{i=l}^rf(i)

lr1011l\leq r\leq10^{11}

這種和質因數有關的奇奇怪怪的函數的前綴和可以試試魔改min_25篩

S(n,j)=i=2n[minp(i)>pj]f(i)S(n,j)=\sum_{i=2}^n[minp(i)>p_j]f(i)

枚舉最小的質因子pkp_k以及次數ee

如果pkp_k不是次小質因子,直接遞歸到S(npke,k)S(\lfloor\frac{n}{p_k^e}\rfloor,k)

否則考慮pkp_k的貢獻

如果是嚴格次小,那麼枚舉最大的質因子

否則就是[e>1][e>1]

S(n,j)=k=j+1pkne=1pken(S(npke,k)+i=pk+1npke[iprime]+[e>1])S(n,j)=\sum_{k=j+1}^{p_k\leq\sqrt n}\sum_{e=1}^{p_k^e\leq n}(S(\lfloor\frac{n}{p_k^e}\rfloor,k)+\sum_{i=p_k+1}^{\lfloor\frac{n}{p_k^e}\rfloor}[i\in prime]+[e>1])

注意pk+1p_k+1可能大於npke\lfloor\frac{n}{p_k^e}\rfloor,要特判一下

然後用min_25的方法預處理出質數個數的前綴和即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#define MAXN 1000005
using namespace std;
const int N=1e6;
int np[MAXN],pl[MAXN],cnt;
void init()
{
	np[1]=1;
	for (int i=2;i<=N;i++)
	{
		if (!np[i]) pl[++cnt]=i;
		for (int j=1,x;(x=i*pl[j])<=N;j++)
		{
			np[x]=1;
			if (i%pl[j]==0) break;
		}
	}
}
typedef long long ll;
ll val[MAXN],n,m;
int key[MAXN],yek[MAXN],tot;
inline int getkey(ll x){return x<=m? key[x]:yek[n/x];}
ll g[MAXN];
ll S(ll n,int j)
{
	if ((ll)pl[j]*pl[j]>n) return 0;
	ll sum=0;
	for (int k=j+1;(ll)pl[k]*pl[k]<=n&&k<=cnt;k++)
		for (ll e=1,v=pl[k];v<=n;e++,v*=pl[k])
			sum+=S(n/v,k)+pl[k]*(max(0ll,g[getkey(n/v)]-k)+(e>1));
	return sum;
}
ll solve(ll N)
{
	m=sqrt(n=N);
	tot=0;
	for (ll l=1,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		val[++tot]=n/l;
		if (val[tot]<=m) key[val[tot]]=tot;
		else yek[n/val[tot]]=tot;
	}
	for (int i=1;i<=tot;i++) g[i]=val[i]-1;
	for (int j=1;j<=cnt;j++)
		for (int i=1;(ll)pl[j]*pl[j]<=val[i];i++)
			g[i]-=g[getkey(val[i]/pl[j])]-j+1;
	return S(n,0);
}
int main()
{
	init();
	ll l,r;
	cin>>l>>r;
	cout<<solve(r)-solve(l-1);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章