hdu5608 function

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

转载于:https://www.cnblogs.com/henry-1202/p/10363375.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值