【2020百度之星初赛一 1008】【hdu6750】Function 题解

题目大意

  记 $f(n)$ 表示 $\sum_{d|n,\ \gcd(n,\frac nd)=1}d$,给定 $n$,求 $\sum_{i=1}^n f(i) \bmod 10^9+7$。

  $n \le 10^{12}$
  多测,10 组数据,20s,32768K 。

首先

  明眼人一看就有

  这显然是个积性函数。

解法1

  一看,积性函数求和;
  再一看,$f(p)=1+p$,意味着 min25 第一步就是求个质数和+质数个数;
  再再一看,给了 20s。

  行,min25,不跟你多 BB

  。。。
  。。。
  。。。
  (半天后)
  。。。

  WOC,0202 年了居然还有内存 32MB 的题!!???

解法2

  于是乎 min25 出于它不可压缩的至少 40MB 的内存,惨遭毒手。。。

  所幸积性函数求和不止一种方法。这里用的是 powerful number,用这个到后面化简起来巨优秀。

  先访问这里学一下 powerful number
  (第一次学就写详细点。。。)
  观察到 $f(p)=1+p$,能跟这个形式凑上的,马上想到 $\sigma(n)=\sum_{d|n}d$ 。
  于是构造 $h(n)=\frac{f(n)}{\sigma(n)}$(狄利克雷卷积的除法),这个 $h(n)$ 就会满足只在 powerful number 处有非 $0$ 值。推一下发现这个 $h(n)$ 长得很好看:

  进一步有

  设 $S_{\sigma}(n) = \sum_{i=1}^n \sigma(i)$,于是有:

  前面 $\mu$ 线筛出来,后面 $S_{\sigma}(\lfloor \frac{n}{i^2} \rfloor)$ 每次分块求:

  总的时间复杂度为

  以优秀的空间+时间打爆一切。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long LL;

const int maxsqrtn=1e6+5, maxp0=80000, maxw0=2e6+5;
const LL mo=1e9+7, inv2=5e8+4;

LL n;
int sqrtn;

int p[maxp0],p0,mu[maxsqrtn];
bool bz[maxsqrtn];
void Prime(int n)
{
mu[1]=1;
fo(i,2,n)
{
if (!bz[i]) p[++p0]=i, mu[i]=-1;
fo(j,1,p0)
{
if ((LL)i*p[j]>n) break;
bz[i*p[j]]=1;
if (i%p[j]==0) break;
else mu[i*p[j]]=-mu[i];
}
}
}

inline LL sum(LL x,LL y) {return (x+y)%mo*((y-x+1)%mo)%mo*inv2%mo;}
LL S(LL n)
{
LL re=0;
for(LL i=1, j; i<=n; i=j+1)
{
LL x=n/i;
j=n/x;
(re+=sum(i,j)*x)%=mo;
}
return re;
}

int T;
int main()
{
Prime(1e6);

scanf("%d",&T);
while (T--)
{
scanf("%lld",&n);
sqrtn=sqrt(n);

LL ans=0;
fo(i,1,sqrtn) if (mu[i]!=0) (ans+=mu[i]*i*S(n/((LL)i*i)))%=mo;

printf("%lld\n",(ans+mo)%mo);
}
}