【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); } }
|