Live2D

Solution -「洛谷 P5325」Min_25 筛

Description

  Link.

  对于积性函数 f(x),有 f(pk)=pk(pk1) (pP,kN+)。求 i=1nf(i)mod(109+7)

  n1010

Solution

  Min_25 筛是不可能的。

  Powerful Number 三步走咯!考虑素数点值:

f(p)=p2p

那么令 g=idφ(点乘号即数值相乘),就有 g(p)=p2p。积性函数的点乘亦为积性函数。

  求 g 的前缀和,杜教筛基础操作,卷上一个 id

[(idφ)id](n)=in(idφ)(i)ni=innφ(i)=n2

自然数平方和易求,丢到杜教筛的式子里,推导后得出

S(n)=n(n+1)(2n+1)6i=2niS(ni)

其中 S(n) 即为 i=1ng(i)

  求 h(pk),可以用 Bell 级数推导。令 Fp,Gp,Hp 分别为 f,g,h 在某一素数 p 的 Bell 级数,则

{Fp=OGF1,p(p1),p2(p21),=11p2z11pz+1Gp=OGF1,p(p1),p3(p1),=1pz1p2z

应用“两函数 Bell 级数的乘法卷积”为“原函数 Dirichlet 卷积之 Bell 级数”的性质,得到

Hp=FpGp=11p2z11pz+11pz1p2z=11p2z1pz+1p2z1pz=11pz1p2z(1pz)2+1p2z1pz

我们仅仅想求 h(pk),即 [zk]Hp,那么

[zk]Hp=[zk]11pz[zk]1p2z(1pz)2[zk]1p2z1pz=pk[(k+1)pkkpk+1]+(pkpk+1)=(k1)(pk+1pk)

  最终,O(n23) 就能求出答案啦。

Code

/* Clearink */

#include <cstdio>
#include <unordered_map>

#define rep( i, l, r ) for ( int i = l, repEnd##i = r; i <= repEnd##i; ++i )
#define per( i, r, l ) for ( int i = r, repEnd##i = l; i >= repEnd##i; --i )

typedef long long LL;

const int MOD = 1e9 + 7, MAXSN = 1e7, INV2 = 500000004, INV6 = 166666668;
int pn, pr[MAXSN + 5], gs[MAXSN + 5], phi[MAXSN + 5];
bool npr[MAXSN + 5];

inline int mul( const long long a, const int b ) { return a * b % MOD; }
inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); }
inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); }

inline void sieve() {
	phi[1] = gs[1] = 1;
	rep ( i, 2, MAXSN ) {
		if ( !npr[i] ) phi[pr[++pn] = i] = i - 1;
		for ( int j = 1, t; j <= pn && ( t = i * pr[j] ) <= MAXSN; ++j ) {
			npr[t] = true;
			if ( !( i % pr[j] ) ) { phi[t] = phi[i] * pr[j]; break; }
			phi[t] = phi[i] * ( pr[j] - 1 );
		}
		gs[i] = add( gs[i - 1], mul( i, phi[i] ) );
	}
}

inline int gSum( const LL n ) {
	static std::unordered_map<LL, int> mem;
	if ( n <= MAXSN ) return gs[n];
	if ( mem.count( n ) ) return mem[n];
	int ret = mul( n % MOD, mul( mul( ( n + 1 ) % MOD,
		( n << 1 | 1 ) % MOD ), INV6 ) );
	for ( LL l = 2, r; l <= n; l = r + 1 ) {
		r = n / ( n / l );
		subeq( ret, mul(
			mul( mul( ( l + r ) % MOD, ( r - l + 1 ) % MOD ), INV2 ),
			gSum( n / l ) ) );
	}
	return mem[n] = ret;
}

LL n;

inline int powerSum( const int pid, LL x, const LL v ) {
	if ( !v ) return 0;
	int ret = 0, p = pr[pid];
	if ( pid == 1 || !( x % pr[pid - 1] ) ) ret = mul( v, gSum( n / x ) );
	if ( pid > pn ) return ret;
	if ( ( x *= p ) > n ) return ret;
	if ( ( x *= p ) > n ) return ret;
	LL pwr = 1ll * p * p;
	if ( pid < pn ) addeq( ret, powerSum( pid + 1, x / pwr, v ) );
	for ( int j = 2; x <= n; ++j, x *= p, pwr *= p ) {
		addeq( ret, powerSum( pid + 1, x,
			mul( v, mul( j - 1, pwr % MOD * ( p - 1 ) % MOD ) ) ) );
	}
	return ret;
}

int main() {
	sieve();
	scanf( "%lld", &n );
	printf( "%d\n", powerSum( 1, 1, 1 ) );
	return 0;
}

posted @   Rainybunny  阅读(81)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示