Problem
Sum
TimeLimit:10Sec
MemoryLimit:128MB
Description
求ans1=∑i=1nϕ(i)和ans2=∑i=1nμ(i)。
n<231,T组询问。
一共T+1行
第1行为数据组数T(T≤10)
第2∼T+1行每行一个非负整数N,代表一组询问
Output
一共T行,每行两个用空格分隔的数ans1,ans2
Sample Output
1 2 3 4 5 6
| 1 1 2 0 22 -2 58 -3 278 -3 1655470 2
|
标签:杜教筛
Solution
杜教筛板题。
首先推杜教筛通式。
对于积性函数f,g,h,若h=f⊗g,即h(n)=∑d∣nf(d)g(dn),那么可以得到
i=1∑nh(i)∴S(n)=i=1∑nd∣i∑f(d)g(dn)=i=1∑ng(i)d=1∑⌊n/i⌋f(d)=i=1∑ng(i)S(⌊in⌋)=i=2∑ng(i)S(⌊in⌋)+g(1)S(n)=g(1)∑i=1nh(i)−∑i=2ng(i)S(⌊in⌋)
这样就可以预处理较小的S后数论分块求解。
然后对于题目中的两问分别推式子:
Calculatei=1∑nμ(i).∵d∣n∑μ(d)=[n=1]=e(n)∴e=μ⊗1⇒S(n)=1−i=2∑nS(⌊in⌋)
Calculatei=1∑nφ(i).∵d∣n∑φ(d)=n=id(n)∴id=φ⊗1⇒S(n)=2n×(n+1)−i=2∑nS(⌊in⌋)
注意将两个答案的求解放在一起,用pair<long,long>
返回,否则可能TLE。
Code
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
| #include <bits/stdc++.h> #define MX 2500000 #define fir first #define sec second #define mp make_pair #define pll pair<lnt,lnt> using namespace std; typedef long long lnt; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } int cnt, pri[MX+5]; lnt phi[MX+5], mu[MX+5]; bool NotPri[MX+5]; map <lnt, lnt> ex1, ex2; void init() { phi[1] = mu[1] = 1; for (int i = 2; i <= MX; i++) { if (!NotPri[i]) pri[cnt++] = i, phi[i] = i-1, mu[i] = -1; for (int j = 0; j < cnt; j++) { if (i*pri[j] > MX) break; NotPri[i*pri[j]] = true; if (i%pri[j]) phi[i*pri[j]] = phi[i]*(pri[j]-1), mu[i*pri[j]] = -mu[i]; else {phi[i*pri[j]] = phi[i]*pri[j], mu[i*pri[j]] = 0; break;} } phi[i] += phi[i-1], mu[i] += mu[i-1]; } } pll sum(lnt n) { if (n <= MX) return mp(phi[n], mu[n]); if (ex1[n]) return mp(ex1[n], ex2[n]); lnt ret1 = 1LL*n*(n+1)/2, ret2 = 1LL; pll t; for (lnt l = 2, r; l <= n; l = r+1) r = n/(n/l), t = sum(n/l), ret1 -= 1LL*(r-l+1)*t.fir, ret2 -= 1LL*(r-l+1)*t.sec; return mp(ex1[n] = ret1, ex2[n] = ret2); } void sol(lnt n) { pll ans = sum(n); printf("%lld %lld\n", ans.fir, ans.sec); } int main() { lnt T, n; read(T), init(); while (T--) read(n), sol(n); return 0; }
|