Du‘s Sieve

由于是没有质量的垃圾博客,就直接放 csdn 了。

对于一个积性函数 f ( n ) f(n) f(n),我们的目标是求出 S ( n ) = ∑ f ( i ) S(n)=\sum f(i) S(n)=f(i),我们选择构造积性函数 g ( n ) g(n) g(n),并以 g ( 1 ) S ( n ) g(1)S(n) g(1)S(n) 的形式间接求出 S ( n ) S(n) S(n)(内心 p.s. 这么 constructive 的东西怎么发明的)。

我们把 Dirichlet Convolution 的形式略改一下, ∑ i = 1 n ( f ∗ g ) ( i ) = ∑ i = 1 n ∑ d ∣ i f ( d ) × g ( i d ) = ∑ d = 1 n f ( d ) ∑ i = 1 n / d g ( i ) = \displaystyle\sum_{i=1}^n(f\ast g)(i)=\sum_{i=1}^n\sum_{d\mid i}f(d)\times g(\frac{i}{d})=\sum_{d=1}^nf(d)\sum_{i=1}^{n/d}g(i)= i=1n(fg)(i)=i=1ndif(d)×g(di)=d=1nf(d)i=1n/dg(i)=,带入 g g g S S S ∑ i = 1 n ∑ d ∣ i g ( d ) f ( i d ) = ∑ i = 1 n g ( i ) S ( n / i ) \displaystyle\sum_{i=1}^n\sum_{d\mid i}g(d)f\left(\frac{i}{d}\right)=\sum_{i=1}^ng(i)S(n/i) i=1ndig(d)f(di)=i=1ng(i)S(n/i)

于是 g ( 1 ) S ( n ) = ( ∑ i = 1 n ( f ∗ g ) ( i ) ) − ( ∑ i = 2 n g ( i ) S ( n / i ) ) \displaystyle g(1)S(n)=\left(\sum_{i=1}^n(f\ast g)(i)\right)-\left(\sum_{i=2}^ng(i)S(n/i)\right) g(1)S(n)=(i=1n(fg)(i))(i=2ng(i)S(n/i))

直接看题捏。

51nod 1227 平均最小公倍数

给定 a , b a,b a,b,求 ∑ i = a b ∑ j = 1 i j ( i , j ) \displaystyle\sum_{i=a}^b\sum_{j=1}^i\frac{j}{(i,j)} i=abj=1i(i,j)j
1 ⩽ a , b ⩽ 1 0 9 1\leqslant a,b\leqslant10^9 1a,b109

考虑前缀答案,容易化成 ∑ d = 1 n ∑ i = 1 n / d ∑ j = 1 i j [ ( i , j ) = 1 ] \displaystyle\sum_{d=1}^n\sum_{i=1}^{n/d}\sum_{j=1}^ij[(i,j)=1] d=1ni=1n/dj=1ij[(i,j)=1],于是我们考虑求 f ( n ) f(n) f(n) = 与小于 n n n 且与其互质的数之和。

于是有, f ( n ) = ∑ i = 1 n i [ ( i , n ) = 1 ] = ∑ i = 1 n i ∑ k ∣ ( i , n ) μ ( k ) = ∑ k ∣ n μ ( k ) × k ∑ i = 1 n / k i = n 2 ( ( ∑ k ∣ n μ ( k ) × n / k ) + ( ∑ k ∣ n μ ( k ) ) ) = n 2 ( φ ( n ) + ϵ ( n ) ) \displaystyle f(n)=\sum_{i=1}^n i[(i,n)=1]=\sum_{i=1}^n i\sum_{k\mid(i,n)}\mu(k)=\sum_{k\mid n}\mu(k)\times k\sum_{i=1}^{n/k}i=\frac{n}{2}\left(\left(\sum_{k\mid n}\mu(k)\times n/k\right)+\left(\sum_{k\mid n}\mu(k)\right)\right)=\frac{n}{2}(\varphi(n)+\epsilon(n)) f(n)=i=1ni[(i,n)=1]=i=1nik(i,n)μ(k)=knμ(k)×ki=1n/ki=2nknμ(k)×n/k+knμ(k)=2n(φ(n)+ϵ(n))

于是原式可化为 n 2 + 1 2 ( ∑ d = 1 n ∑ i = 1 n / d i × φ ( i ) ) \displaystyle\frac{n}{2}+\frac{1}{2}\left(\sum_{d=1}^n\sum_{i=1}^{n/d}i\times\varphi(i)\right) 2n+21d=1ni=1n/di×φ(i),观察到 id ( i ) ∗ i × φ ( i ) = ∑ d ∣ i φ ( i ) × i / d = i 2 \displaystyle\textit{id}(i)\ast i\times\varphi(i)=\sum_{d\mid i}\varphi(i)\times i/d=i^2 id(i)i×φ(i)=diφ(i)×i/d=i2,套一个二次方和公式即可杜教筛了。logical & reasonable!

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define cmin(x, ...) x = min({x, __VA_ARGS__})
#define cmax(x, ...) x = max({x, __VA_ARGS__})
#define fors(i, l, r, ...) for(int i = (l), REP##i = (r), ##__VA_ARGS__; i <= REP##i; ++i)
#define dfors(i, r, l, ...) for(int i = (r), REP##i = (l), ##__VA_ARGS__; i >= REP##i; --i)
const int P = 1e9+7;
struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x^(x>>30))*0xbf58476d1ce4e5b9;
        x = (x^(x>>27))*0x94d049bb133111eb;
        return x^(x>>31);
    }
    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x+FIXED_RANDOM);
    }
};
signed main() {
    ios::sync_with_stdio(0), cin.tie(0);
    // f(n) = sum(1~n) i*phi(i)
    // id*f = sum(1~n) i^2
    // S(n) = sum(1~n) i^2 - sum(2~n) S(n/i)*i
    const function<int(const ll)> p_f = [&](const ll x) {
        static const ll THRESHOLD = 1e7;
        static unordered_map<ll, int, custom_hash> g_f;
        static auto l_f = [&](const int n) {
            vector<int> f(n+1), prime;
            vector<bool> not_prime(n+1);
            f[1] = 1;
            fors(i, 2, n) {
                if(not_prime[i] == 0) f[i] = i-1,prime.emplace_back(i);
                for(const int p : prime) {
                    if(i > n/p) break;
                    not_prime[i*p] = 1;
                    if(i%p == 0) {
                        f[i*p] = ll(f[i])*p%P;
                        break;
                    }
                    f[i*p] = ll(f[i])*f[p]%P;
                }
            }
            fors(i, 1, n) f[i] = (f[i-1]+ll(f[i])*i%P)%P;
            return f;
        }(THRESHOLD);
        if(x <= THRESHOLD) return l_f[x];
        if(g_f.count(x)) return g_f[x];
        int _x = x%P, res = ll(_x)*((2*_x+1)%P)%P*(_x+1)%P*166666668%P; // sum(1~n) i^2
        for(ll l = 2, r; l <= x; l = r+1) {
            r = x/(x/l);
            res -= (ll)p_f(x/l)*(r-l+1)%P*(l+r)%P*(P+1)/2%P, res %= P;
        }
        return g_f[x] = (res+P)%P;
    };
    auto cal = [&](const ll x) {
        int res = x;
        for(ll l = 1, r; l <= x; l = r+1) {
            r = x/(x/l);
            res += (ll)p_f(x/l)*(r-l+1)%P, res %= P;
        }
        (res += P) %= P;
        return ll(res)*(P+1)/2%P;
    };
    ll a, b; cin >> a >> b;
    cout << (cal(b)-cal(a-1)+P)%P << "\n";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值