题面
http://acm.hdu.edu.cn/showproblem.php?pid=5942
题解
前置知识
- 线性筛积性函数:https://www.cnblogs.com/zhoushuyu/p/8275530.html
- 莫比乌斯反演:《具体数学:计算机科学基础》4.9节
- 莫比乌斯反演的基础应用: https://www.cnblogs.com/xh092113/p/12268356.html
- 数论分块: https://www.cnblogs.com/xh092113/p/12269753.html
引理
[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;
}