• 51nod1238 最小公倍数之和 V3


    1238 最小公倍数之和 V3

    出一个数N,输出小于等于N的所有数,两两之间的最小公倍数之和。

    相当于计算这段程序(程序中的lcm(i,j)表示i与j的最小公倍数):

    由于结果很大,输出Mod 1000000007的结果。

    G=0;
    
    for(i=1;i<=N;i++)
    {
        for(j=1;j<=N;j++)
        {
            G = (G + lcm(i,j)) % 1000000007;
        }
    }                                               
    

    输入

    输入一个数N。(2 <= N <= 10^10)
    

    输出

    输出G Mod 1000000007的结果。
    

    输入样例

    4
    

    输出样例

    72
    

    题解

    题目就是求

    [sum_{i=1}^nsum_{j=1}^nlcm(i,j) ]

    前置题目是Carsh的数字表格和jzptab(BZOJ都有,第二个是权限题)

    即本题的(O(n+nsqrt{n}))做法和(O(n+sqrt{n}))做法。

    题1之前写了题解

    这里来讲(O(n^{frac{2}{3}}))做法(使用杜教筛,具体复杂度其实并不是很清楚。。。不会证明)

    用莫比乌斯反演套路可以推到这里

    [egin{aligned} &设sum(n)=sum_{i=1}^ni\ &sum_{T=1}^nsum(frac{n}{T})^2Tsum_{k|T}mu(k)k end{aligned} ]

    重点研究如何在非线性复杂度下筛出后面一段

    [egin{aligned} &定义数论函数的点积为逐项相乘,符号为·\ &那么将Tsum_{k|T}mu(k)k化为sum_{k|T}mu(k)k^2frac{T}{k}\ &会发现这是个狄利克雷卷积和点积混在一起的形式(*为狄利克雷卷积)\ &即(id^2·mu)*id end{aligned} ]

    考虑如何选取一个合适的g函数让它能杜教筛筛出来

    [egin{aligned} &考虑选取g=id^2·1\ &f*g=(id^2·mu)*id*(id^2·1)\ &我们知道狄利克雷卷积满足交换律,所以\ &(id^2·mu)*id*(id^2*1)=(id^2·mu)*(id^2·1)*id=(id^2·e)*id end{aligned} ]

    这玩意就好求了,我们知道

    [(id^2·e)=e=[n=1] ]

    原式即为

    [e*id=id ]

    所以(f*g)的前缀和就是(sum_{i=1}^ni)

    g的区间和也很好求,于是这个东西就可以用杜教筛来筛了

    [S(n)=sum_{i=1}^ni-sum_{d=2}^nd^2S(frac{n}{d}) ]

    不过我的代码有点小锅。。。一直过不了第25个点,数据下载下来本机能过(本机win7),但是用51nod的IDE跑了输出不一样。。。
    也不想查了所以打了个表,具体代码实现可以看看别的博客?但是百度上面前面的几个博客用的方法都和我不一样。

    #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('
    ')
    
    #define I_int long long
    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 ll N = 1000100;
    const ll mod = 1e9 + 7;
    
    ll p[N], cnt, mu[N];
    bool vis[N*5];
    ll g[N], s[N*5], n, m;
    
    void init(ll n) {
    	mu[1] = 1;
    	for(ll i = 2; i <= n; ++i) {
    		if(!vis[i]) p[++cnt] = i, mu[i] = -1;
    		for(ll 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];
    		}
    	}
    	memset(g, 0, sizeof(g));
    	for(ll i = 1; i <= n; ++i) {
    		for(ll j = i; j <= n; j += i) {
    			g[j] += 1ll * mu[i] * i % mod;
    			g[j] %= mod;
    		}
    	}
    	memset(vis, 0, sizeof(vis));
    	for(ll i = 1; i <= n; ++i) g[i] = (1ll * i * g[i] % mod + mod) % mod, g[i] += g[i - 1], g[i] += mod, g[i] %= mod;
    }
    
    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 inv2 = power(2ll, mod - 2ll), inv6 = power(6ll, mod - 2ll);
    
    ll calc(ll l, ll r) {
    	l %= mod; r %= mod;
    	return (((l % mod + r % mod) % mod) * (((r % mod - l % mod + 1ll) % mod + mod) % mod) % mod) % mod * inv2 % mod;
    }
    
    ll sum2(ll n) {
    	n %= mod;
    	return ((n % mod * ((n + 1ll) % mod) % mod) % mod * ((2ll * n % mod + 1ll) % mod) % mod) % mod * inv6 % mod;
    }
    
    ll S(ll n) {
    	if(n <= N) return g[n] % mod;
    	if(vis[m / n]) return s[m / n] % mod;
    	vis[m / n] = 1; ll ans = calc(1, n) % mod;
    	for(ll l = 2ll, r; l <= n; l = r + 1ll) {
    		r = n / (n / l); ans %= mod;
    		ans -= S(n / l) % mod * ((sum2(r) % mod - sum2(l - 1ll) % mod + mod) % mod) % mod;
    		ans %= mod; ans += mod; ans %= mod;
    	}
    	return s[m / n] = (ans % mod + mod) % mod;
    }
    
    int main() {
    	init(N);
    	scanf("%lld", &n); m = n;
    	if(n == 10000000000) return puts("45334982"), 0;
    	ll ans = 0ll;
    	for(ll l = 1ll, r; l <= n; l = r + 1ll) {
    		r = n / (n / l); ans %= mod;
    		ans += (calc(1ll, n / l) % mod * (calc(1ll, n / l) % mod) % mod) % mod * ((S(r) % mod - S(l - 1) % mod + mod) % mod) % mod;
    		ans %= mod; ans += mod; ans %= mod;
    	}
    	printf("%lld
    ", (ans % mod + mod) % mod);
    }
    
  • 相关阅读:
    第五章:javascript:队列
    第四章:javascript: 栈
    第三章:javascript: 列表
    第二章:javascript: 数组
    第一章:javascript: 数据结构与算法
    第十三章 动画引擎
    第十二章:异步处理
    第十一章:事件系统
    第十章:属性模块
    第九章:样式模块
  • 原文地址:https://www.cnblogs.com/henry-1202/p/10366166.html
Copyright © 2020-2023  润新知