Description
There is a function f(x),which is defined on the natural numbers set N,satisfies the following eqaution
N2−3N+2=∑d|Nf(d)
calulate ∑Ni=1f(i) mod 109+7
Input
the first line contains a positive integer T,means the number of the test cases.
next T lines there is a number N
T≤500,N≤109
only 5 test cases has N>106
.
Output
Tlines,each line contains a number,means the answer to the i
-th test case.
Sample Input
1
3
Sample Output
2
$1^2-3*1+2=f(1)=0$
$2^2-3*2+2=f(2)+f(1)=0->f(2)=0$
$3^2-3*3+2=f(3)+f(1)=2->f(3)=2$
$f(1)+f(2)+f(3)=2$
Solution
两种方法:杜教筛,杜教筛+莫比乌斯反演
1.杜教筛+莫比乌斯反演
这貌似是我第一次真正意义上用莫比乌斯反演公式。。。
设\(F(n)=\sum_{d|n}f(d)=n^2-3n+2\)
则有\(f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})\)
\[ \begin{aligned} &\sum_{i=1}^{n}f(i)\\ &=\sum_{i=1}^{n}\sum_{d|i}\mu(d)F(\frac{n}{d})\\ &=\sum_{d=1}^n\mu(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}F(i) \end{aligned} \]
前面那个\(\mu(d)\)杜教筛,后面那个推一下可以\(O(1)\)
\(\sum_{i=1}^n{i^2-3i+2}=\frac{n(n-1)(n-2)}{3}\)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <deque>
#include <map>
#include <set>
#define ll long long
#define inf 0x3f3f3f3f
#define il inline
namespace io {
#define in(a) a = read()
#define out(a) write(a)
#define outn(a) out(a), putchar('\n')
#define I_int ll
inline I_int read() {
I_int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
char F[200];
inline void write(I_int x) {
if (x == 0) return (void) (putchar('0'));
I_int tmp = x > 0 ? x : -x;
if (x < 0) putchar('-');
int cnt = 0;
while (tmp > 0) {
F[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while (cnt > 0) putchar(F[--cnt]);
}
#undef I_int
}
using namespace io;
using namespace std;
const int N = 5e6;
const ll mod = 1e9 + 7;
ll n, m;
bool vis[N+10];
int p[N/10], cnt;
int mu[N], s[30000];
void init(int n) {
mu[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!vis[i]) p[++cnt] = i, mu[i] = -1;
for(int j = 1; j <= cnt && i * p[j] <= n; ++j) {
vis[i * p[j]] = 1;
if(i % p[j] == 0) break;
mu[i * p[j]] = -mu[i];
}
}
for(int i = 1; i <= n; ++i) mu[i] += mu[i - 1];
}
int S(ll n) {
if(n <= N) return mu[n];
if(vis[m / n]) return s[m / n];
vis[m / n] = 1;
int ans = 1;
for(ll l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
ans -= (r - l + 1) * S(n / l);
ans %= mod; ans += mod; ans %= mod;
}
return s[m / n] = ans;
}
ll power(ll a, ll b) { ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod; b >>= 1;
}
return ans;
}
ll inv3 = power(3, mod - 2);
ll calc(ll n) {
return n * (n - 1) % mod * (n - 2) % mod * inv3 % mod;
}
int main() {
init(N);
int T = read();
while(T--) {
n = read();
memset(vis, 0, sizeof(vis));
m = n;
ll ans = 0;
for(ll l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
ans += 1ll * (S(r) - S(l - 1) + mod) % mod * calc(n / l) % mod ;
ans %= mod;
}
printf("%lld\n", ans);
}
}
2.杜教筛
现在才知道杜教筛可以筛普通数论函数,不一定要积性函数。
那么就很简单了,套路的给\(f\)卷上\(1\),则有\(f*1=g=n^2-3n+2\)
至于预处理g的前缀和,这玩意不是积性函数不能线性筛。但是可以\(nlogn\)暴力筛出来。方法很多,因为我是写了方法1再来写方法2的所以我直接又反演了一下来筛。。。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <deque>
#include <map>
#include <set>
#define ll long long
#define inf 0x3f3f3f3f
#define il inline
namespace io {
#define in(a) a = read()
#define out(a) write(a)
#define outn(a) out(a), putchar('\n')
#define I_int ll
inline I_int read() {
I_int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
char FF[200];
inline void write(I_int x) {
if (x == 0) return (void) (putchar('0'));
I_int tmp = x > 0 ? x : -x;
if (x < 0) putchar('-');
int cnt = 0;
while (tmp > 0) {
FF[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while (cnt > 0) putchar(FF[--cnt]);
}
#undef I_int
}
using namespace io;
using namespace std;
const int N = 1e6;
const ll mod = 1e9 + 7;
ll n, m;
bool vis[N+10];
int p[N/10], cnt;
ll s[N], F[N];
ll power(ll a, ll b) { ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod; b >>= 1;
}
return ans;
}
ll inv3 = power(3, mod - 2);
ll calc(ll n) {
n %= mod;
return n * (n - 1) % mod * (n - 2) % mod * inv3 % mod;
}
int mu[N];
void init(int n) {
mu[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!vis[i]) p[++cnt] = i, mu[i] = -1;
for(int j = 1; j <= cnt && i * p[j] <= n; ++j) {
vis[i * p[j]] = 1;
if(i % p[j] == 0) break;
mu[i * p[j]] = -mu[i];
}
}
for(int i = 1; i <= n; ++i) {
ll g = (ll)(((ll)i * i % mod - 3ll * i % mod + 2ll) % mod + mod) % mod;
for(int j = i; j <= n; j += i) {
F[j] += 1ll * mu[j / i] * g % mod;
F[j] %= mod;
}
}
for(int i = 1; i <= n; ++i) F[i] += F[i - 1], F[i] %= mod;
}
ll S(ll n) {
if(n <= N) return F[n];
if(vis[m / n]) return s[m / n];
vis[m / n] = 1;
ll ans = calc(n);
for(ll l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
ans -= (r - l + 1) * S(n / l) % mod;
ans %= mod; ans += mod; ans %= mod;
}
return s[m / n] = (ans % mod + mod) % mod;
}
int main() {
init(N);
int T = read();
while(T--) {
n = read();
memset(vis, 0, sizeof(vis));
m = n;
printf("%lld\n", (S(n) + mod) % mod);
}
}