[HDU5942]Just a Math Problem(莫比乌斯反演)

题面

http://acm.hdu.edu.cn/showproblem.php?pid=5942

题解

前置知识

引理

[2^{f(n)}={sumlimits_{d1*d2=n}[(d1,d2)=1]} ]

  • 此处的f(n)即为题目中的f(n)。

证明:设(n={prod_{i=1}^{k}}{p_i^{alpha_i}}),各(p_i)是质数。

[RHS = {prodlimits_{i=1}^{k}}{sumlimits_{eta_1+eta_2=alpha_i}}[min(eta_1,eta_2)=0] ]

[={prodlimits_{i=1}^{k}}2=2^k=LHS ]

引理得证。

回原题

[{sumlimits_{i=1}^{n}}2^{f(i)} ]

[={sumlimits_{i=1}^{n}}{sumlimits_{d1*d2=i}}[(d1,d2)=1] ]

[={sumlimits_{d1*d2{leq}n}}[(d1,d2)=1] ]

[={sumlimits_{d1*d2{leq}n}}{ }{sumlimits_{d|(d1,d2)}}{mu(d)} ]

[={sumlimits_{d}}{mu(d)}{sumlimits_{d1*d2{leq}n}}[d|d1][d|d2] ]

[={sumlimits_{d}}{mu(d)}*s({lfloor}{frac{n}{d^2}}{ floor}) ]

[={sumlimits_{d{leq}{sqrt{n}}}}{mu(d)}*s({lfloor}{frac{n}{d^2}}{ floor}) ]

其中s(n)表示({sum_{i=1}^{n}}{lfloor}{frac{n}{i}}{ floor})。求s(n)是经典的数论分块问题,可以(O(sqrt{n}))解决。

总时间复杂度(O(T({sqrt{frac{n}{1^2}}}+{sqrt{frac{n}{2^2}}}+…+{sqrt{frac{n}{{sqrt{n}}^2}}})))

[=O(T{sqrt{n}}H({sqrt{n}}))$$(H为调和级数) $$=O(T{sqrt{n}}logn)]

  • P.S.此题巨卡无比;需要各种卡常技巧;比如给s加一些记忆化,mu=0时跳过s的计算,以及尽一切可能避免mod等等。

代码

#include<bits/stdc++.h>

using namespace std;

#define sqrtN 1000000
#define rg register
#define ll long long
#define mod 1000000007

const ll T = 20000000;

namespace ModCalc{
	inline void Inc(ll &x,ll y){
		x += y;if(x >= mod)x -= mod;
	}
	
	inline void Dec(ll &x,ll y){
		x -= y;if(x < mod)x += mod;
	}
	
	inline ll Add(ll x,ll y){
		Inc(x,y);return x;
	}
	
	inline ll Sub(ll x,ll y){
		Dec(x,y);return x;
	}
}
using namespace ModCalc;

inline ll read(){
	ll s = 0,ww = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
	while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
	return s * ww;
}

inline void write(ll x){
	if(x < 0)x = -x,putchar('-');
	if(x > 9)write(x / 10);
	putchar('0' + x % 10);
}

ll pn;
ll pri[sqrtN+5],mu[sqrtN+5];
bool isp[sqrtN+5];
ll S[T+5];

inline void Eular(){
	mu[1] = 1;
	for(rg ll i = 2;i <= sqrtN;i++)isp[i] = 1;
	for(rg ll i = 2;i <= sqrtN;i++){
		if(isp[i])pri[++pn] = i,mu[i] = -1;
		for(rg ll j = 1;i * pri[j] <= sqrtN;j++){
			isp[i*pri[j]] = 0;
			if(i % pri[j])mu[i*pri[j]] = -mu[i];
			else{
				mu[i*pri[j]] = 0;
				break;
			}
		}
	}
}

inline ll s(ll n){
	if(n <= T && S[n])return S[n];
	ll L,R = 0;
	ll ans = 0;
	while(R < n){
		L = R + 1,R = n / (n / L);
		ans = (ans + (R - L + 1) * (n / L)) % mod;
	}
	if(n <= T)S[n] = ans;
	return ans;
}

int main(){
	Eular();
	ll c = 1;
	ll T = read();
	while(T--){
		printf("Case #%lld: ",c++);
		ll n = read();
		ll ans = 0;
		for(rg ll i = 1;i * i <= n;i++)if(mu[i])ans = (ans + mu[i] * s(n/i/i)) % mod;
		write((ans + mod) % mod),putchar('
');
	}
	return 0;
}

原文地址:https://www.cnblogs.com/xh092113/p/12289949.html