求 \(\sum_{i=1}^N\sum_{j=1}^Nf^k(\gcd(i,j))\),其中 \(f(x)\) 表示 \(x\) 的第二大质因子,每个质因子算多次,即 \(f(4)=f(6)=2\),定义 \(f(1)=0,f(Prime)=1\)。
众所周知 Min_25 筛的本质是用 DP 求出所有 \(S(\lfloor\frac{n}{1}\rfloor),S(\lfloor\frac{n}{2}\rfloor)...\) 这 \(2\sqrt{n}\) 个值。如果可以较好的处理每个数质因子之间的关系的话,是不要求所筛函数是积性函数的,这个题就是一个典型例子。
直接设 \(f^k(n)=\sum_{d|n}g(d)\),莫比乌斯反演得到 \(g(n)=\sum_{d|n}f^k(d)\mu(\frac{n}{d})\)。原式变成 \(\sum_{d=1}^ng(d)\lfloor\frac{n}{d}\rfloor^2\)。
后面直接整除分块,现在就只需要求 \(g\) 的前缀和。
设 \(S(n)=\sum_{i=1}^ng(i)\),那么 \(S(n)=\sum_{i=1}^n\sum_{d|n}\mu(d)f^k(\frac{n}{d})=\sum_{d=1}^n\mu(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f^k(i)\)。后面的求和式又可以整除分块。而前面求 \(\mu\) 的前缀和可以用杜教筛(应该也只能用杜教筛)。
考虑怎么求 \(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f^k(i)\)。可以发现 Min_25 筛求积性函数和的时候,每次是剥离了一个数的最小质因子。在这个题中,如果这个最小质因子恰好是次大质因子,那么就可以直接计算贡献,否则贡献就已经在之前算过了。所以我们设 \(F(n,x)\) 表示 \(n\) 以内所有质因子大于等于 \(Prime_x\) 的合数的 \(f^k(x)\) 的和,\(G(n)\) 表示 \(n\) 以内的质数个数。类似于 Min_25 筛的,\(F,G\) 只有 \(2\sqrt{n}\) 个值。
\(G\) 是一个经典的 DP,在此就不再赘述。
考虑求 \(F\),有 \(F(n,x)=F(n,x+1)+\sum_{e=1}\left(F(\frac{n}{p_x^e},x+1)+p_x^k\left(G(\frac{n}{p_x^e})-(x-1)\right)\right)\),即分最小质因子大于 \(x\) 和最小质因子恰好为 \(x\) 分别处理。
最后的真实的 \(\sum_{i=1}^nf^k(i)\) 就是 \(F(n)+G(n)\)。
总复杂度暂时还不会分析,但是 Min_25 的预处理是约 \(O(n^\frac{3}{4})\),真实求值的时候要用两个整除分块加杜教筛,复杂度可能会达到 \(O(n^{\frac{7}{8}})\)(当然这是瞎扯)。总之能过。
| 12
 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
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 
 | #include <bits/stdc++.h>#define debug(...) fprintf(stderr, __VA_ARGS__)
 #define RI register int
 typedef long long LL;
 
 #define FILEIO(name) freopen(name".in", "r", stdin), freopen(name".out", "w", stdout);
 
 using namespace std;
 
 int const MAXN = 1e6 + 5;
 int n, k, sq;
 int Prime[MAXN], tot, miu[MAXN], Smiu[MAXN];
 char Notprime[MAXN];
 
 void Euler(int Max) {
 miu[1] = Smiu[1] = 1;
 for (RI i = 2; i <= Max; ++i) {
 if (!Notprime[i])
 Prime[++tot] = i, miu[i] = -1;
 for (RI j = 1; j <= tot && i * Prime[j] <= Max; ++j) {
 Notprime[i * Prime[j]] = 1;
 if (i % Prime[j] == 0) break;
 miu[i * Prime[j]] = miu[i] * -1;
 }
 Smiu[i] = Smiu[i - 1] + miu[i];
 }
 }
 namespace DuDuDu {
 map <int, unsigned int> mp;
 unsigned int S(int n) {
 if (n <= MAXN - 5) return Smiu[n];
 if (mp.count(n)) return mp[n];
 unsigned ans = 1;
 for (RI l = 2, r; l <= n; l = r + 1) {
 r = n / (n / l);
 ans -= (r - l + 1) * S(n / l);
 }
 return mp[n] = ans;
 }
 }
 namespace InitF {
 
 
 
 int const MX = 1e5 + 5;
 int id1[MX], id2[MX], val[MX];
 unsigned int G[MX], F[MX], Ans[MX];
 inline int Getid(int x) { return x <= sq ? id1[x] : id2[n / x]; }
 unsigned int qpow(unsigned int a, int k) {
 unsigned int re = 1;
 for (; k; k >>= 1, a *= a)
 if (k & 1) re *= a;
 return re;
 }
 void Work() {
 int cnt = 0;
 for (RI l = 1, r; l <= n; l = r + 1) {
 r = n / (n / l);
 int x = (n / l);
 if (x <= sq) id1[x] = ++cnt, val[cnt] = x;
 else     id2[n / x] = ++cnt, val[cnt] = x;
 }
 for (RI i = 1; i <= cnt; ++i)
 G[i] = val[i] - 1;
 int x;
 for (x = 1; Prime[x] * Prime[x] <= val[1]; ++x)
 for (RI i = 1; i <= cnt; ++i) {
 if (Prime[x] * Prime[x] > val[i]) break;
 G[i] = G[i] - (G[Getid(val[i] / Prime[x])] - (x - 1));
 }
 for (; x; --x) {
 for (RI i = 1; i <= cnt; ++i) {
 LL cur = Prime[x];
 while (cur * Prime[x] <= val[i]) {
 F[i] += F[Getid(val[i] / cur)];
 F[i] += (G[Getid(val[i] / cur)] - (x - 1)) * qpow(Prime[x], k);
 cur *= Prime[x];
 }
 }
 }
 for (RI i = 1; i <= cnt; ++i)
 Ans[i] = F[i] + G[i];
 }
 }
 unsigned int SG(int n) {
 unsigned int ans = 0;
 for (RI l = 1, r; l <= n; l = r + 1) {
 r = n / (n / l);
 unsigned int L = DuDuDu :: S(l - 1), R = DuDuDu :: S(r);
 ans += (R - L) * (InitF :: Ans[InitF :: Getid(n / l)]);
 }
 return ans;
 }
 
 int main() {
 
 #ifdef LOCAL
 FILEIO("a");
 #endif
 
 Euler(1e6);
 cin >> n >> k;
 sq = sqrt(n);
 InitF :: Work();
 unsigned int ans = 0;
 for (RI l = 1, r; l <= n; l = r + 1) {
 r = n / (n / l);
 unsigned int L = SG(l - 1), R = SG(r);
 ans += (R - L) * (n / l) * (n / l);
 }
 cout << ans << endl;
 
 return 0;
 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 |