zoukankan      html  css  js  c++  java
  • BZOJ2154: Crash的数字表格

    Description

    今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数。例如,LCM(6, 8) = 24。回到家后,Crash还在想着课上学的东西,为了研究最小公倍数,他画了一张NM的表格。每个格子里写了一个数字,其中第i行第j列的那个格子里写着数为LCM(i, j)。一个45的表格如下: 1 2 3 4 5 2 2 6 4 10 3 6 3 12 15 4 4 12 4 20 看着这个表格,Crash想到了很多可以思考的问题。不过他最想解决的问题却是一个十分简单的问题:这个表格中所有数的和是多少。当N和M很大时,Crash就束手无策了,因此他找到了聪明的你用程序帮他解决这个问题。由于最终结果可能会很大,Crash只想知道表格里所有数的和mod 20101009的值。

    Input

    输入的第一行包含两个正整数,分别表示N和M。

    Output

    输出一个正整数,表示表格中所有数的和mod 20101009的值。

    Sample Input

    4 5

    Sample Output

    122
    【数据规模和约定】
    100%的数据满足N, M ≤ 10^7。

    Solution

    莫比乌斯反演裸题。

    [large egin{aligned} &sum_{i=1}^{n}sum_{j=1}^{m}lcm(i,j)\ &=sum_{d=1}^{n}sum_{i=1}^{n}sum_{j=1}^mfrac{ij}{d}[(i,j)=1]\ &=sum_{d=1}^{n}sum_{i=1}^{frac{n}{d}}sum_{j=1}^{frac{m}{d}}ijd[(i,j)=1]\ &=sum_{d=1}^{n}sum_{i=1}^{frac{n}{d}}sum_{j=1}^{frac{m}{d}}ijdsum_{k|gcd(i,j)}mu(k)\ &=sum_{d=1}^{n}dsum_{k=1}^{n}mu(k) k^2sum_{i=1}^{frac{n}{kd}}isum_{j=1}^{frac{m}{kd}}j end{aligned} ]

    式子推出来之后两次数论分块即可,注意不要溢出就好
    复杂度(O(n))

    #include <bits/stdc++.h>
    using namespace std;
    #define mod 20101009
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const int N = 1e7 + 10;
    
    ll mu[N], p[N], cnt;
    ll n, m, sum[N];
    bool vis[N];
    
    void pre() {
    	ll limit = max(n, m);
    	mu[1] = sum[1] = 1;
    	for(ll i = 2; i <= limit; ++i) {
    		if(!vis[i]) p[++cnt] = i, mu[i] = -1;
    		for(int j = 1; j <= cnt && i * p[j] <= limit; ++j) {
    			vis[i * p[j]] = 1;
    			if(i % p[j] == 0) {mu[i * p[j]] = 0; break;}
    			mu[i * p[j]] = -mu[i];
    		}
    		sum[i] = sum[i - 1] + mu[i] * i % mod * i % mod;
    		sum[i] %= mod;
    	}
    }
    
    ll sum1(ll x, ll y) {
    	return 1ll * (((x * (x + 1) / 2) % mod) * ((y * (y + 1) / 2) % mod)) % mod;
    }
    
    ll calc(ll a, ll b) {
    	if(a > b) swap(a, b);
    	ll s = 0;
    	for(ll r, l = 1; l <= a; l = r + 1) {
    		r = min(a / (a / l), b / (b / l)); 
    		s = (1ll * s + 1ll * (sum[r] - sum[l - 1] + mod) % mod * sum1(a / l, b / l) % mod) % mod;
    	}
    	return s % mod;
    }
    
    int main() {
    	scanf("%lld%lld", &n, &m);
    	pre();
    	ll ans = 0;
    	if(n > m) swap(n, m);
    	for(ll r, l = 1; l <= n; l = r + 1) {
    		r = min(n / (n / l), m / (m / l));
    		ans += 1ll * calc(n / l, m / l) % mod * (1ll * (r - l + 1) * (l + r) / 2 % mod) % mod;
    		ans %= mod;
    	}
    	printf("%lld
    ", (ans % mod + mod) % mod);
    	return 0;
    }
    
  • 相关阅读:
    OpenStreetMap/Google/百度/Bing瓦片地图服务(TMS)
    【APM】Pinpoint 监控告警(三)
    【APM】Pinpoint 使用教程(二)
    【APM】Pinpoint 安装部署(一)
    【HBase】HBase 单机版安装及使用
    【SpringBoot】SpringBoot快速入门(一)
    【Java】Swagger快速入门
    【WebSocket】WebSocket快速入门
    【JS】AJAX跨域-被调用方与调用方解决方案(二)
    【JS】AJAX跨域-JSONP解决方案(一)
  • 原文地址:https://www.cnblogs.com/henry-1202/p/10327255.html
Copyright © 2011-2022 走看看