Live2D

Solution -「LOJ #6053」简单的函数

Description

  Link.

  积性函数 f 满足 f(pc)=pc (pP,cN+),求 i=1nf(i)mod(109+7)

Solution

  首先,考虑 f 的素数点值:

f(p)={3,p=2p1,otherwise

p1 联想到 φ(p)=p1,可惜 φ(2)=1。干脆一点,我们直接强行把 φ 的偶数点值乘上 3,令

g(n)={φ(n),2n3φ(n),otherwise

显然它也是积性函数。

  接着,求 g 的前缀和。其前缀和为 φ 的前缀和加上两倍偶数点的 φ 前缀和。记

S(n)=i=1nφ(2i)=i=1n[2i]φ(i)+2i=1n[2i]φ(i)=S(n2)+i=1nφ(i)

杜教筛处理 φ 的前缀,S 就能在可观(我不会算 qwq)的复杂度内预处理出来,继而也得到了 gO(n) 个前缀和。

  此外,我们还需要求 h(i),即求 h(pc) (c>1)。考虑 f(pc) 与它的关系:

f(pc)=i=0ch(pi)g(pci)    h(pc)=f(pc)i=0c1h(pi)g(pci)

顺手把 O(nlnlnn)n 以内素数的倒数和的规模是 O(lnlnn))个 h(pc) 也预处理出来,最后 O(n) 搜索 Powerful Number 就能求出答案啦!

Code

/* Clearink */

#include <cmath>
#include <cstdio>
#include <vector>
#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 MAXS = 1e7, MAXSN = 1e5, MOD = 1e9 + 7, INV2 = 500000004;
int pn, pr[MAXS + 5], phi[MAXS + 5], phis[MAXS + 5];
bool npr[MAXS + 5];
std::vector<int> gpr[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] = phis[1] = 1;
	rep ( i, 2, MAXS ) {
		if ( !npr[i] ) phi[pr[++pn] = i] = i - 1;
		for ( int j = 1, t; j <= pn && ( t = i * pr[j] ) <= MAXS; ++j ) {
			npr[t] = true;
			if ( !( i % pr[j] ) ) { phi[t] = phi[i] * pr[j]; break; }
			phi[t] = phi[i] * ( pr[j] - 1 );
		}
		phis[i] = add( phis[i - 1], phi[i] );
	}
}

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

inline int ephiSum( const LL n ) {
	if ( !n ) return 0;
	return add( ephiSum( n >> 1 ), phiSum( n ) );
}

LL n;
int sn, sum[MAXSN * 2 + 5];

inline void initInvG() {
	rep ( i, 1, pn ) {
		if ( 1ll * pr[i] * pr[i] > n ) break;
		std::vector<int>& curg( gpr[i] );
		curg.push_back( 1 ), curg.push_back( 0 );
		LL pwr = 1ll * pr[i] * pr[i];
		for ( int j = 2; pwr <= n; ++j, pwr *= pr[i] ) {
			int g = pr[i] ^ j;
			LL pwc = pr[i];
			for ( int k = j - 1; ~k; --k, pwc *= pr[i] ) {
				subeq( g,
					mul( ( pwc / pr[i] * ( pr[i] ^ 1 ) ) % MOD, curg[k] ) );
			}
			curg.push_back( g );
		}
	}
}

inline int powerSum( const int pid, LL x, const int g ) {
	if ( !g ) return 0;
	int ret = 0, p = pr[pid];
	if ( pid == 1 || !( x % pr[pid - 1] ) ) {
		addeq( ret, mul( g, x > sn ? sum[n / x] : sum[sn + x] ) );
	}
	if ( ( x *= p ) > n ) return ret;
	if ( ( x *= p ) > n ) return ret;
	addeq( ret, powerSum( pid + 1, x / ( 1ll * p * p ), g ) );
	for ( int i = 2; x <= n; ++i, x *= p ) {
		addeq( ret, powerSum( pid + 1, x, mul( g, gpr[pid][i] ) ) );
	}
	return ret;
}

int main() {
	sieve();
	scanf( "%lld", &n ), sn = sqrt( 1. * n );
	rep ( i, 1, sn ) sum[i] = add( phiSum( i ), mul( 2, ephiSum( i >> 1 ) ) );
	rep ( i, 1, sn ) {
		sum[i + sn] = add( phiSum( n / i ), mul( 2, ephiSum( n / i >> 1 ) ) );
	}
	initInvG();
	printf( "%d\n", powerSum( 1, 1, 1 ) );
	return 0;
}

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