Luogu P1829 [National Training Team] Crash's digital table Mobius inversion

Topic description

In today's math class, Crash children learned the least common multiple (Least Common Multiple). For two positive integers a and b, LCM(a, b) represents the smallest positive integer that divides both a and b. For example, LCM(6, 8) = 24.

After returning home, Crash was still thinking about what he had learned in class. In order to study the least common multiple, he drew a table of N*M. A number is written in each grid, and the grid in the i-th row and the j-th column is written as LCM(i, j). A 4*5 form is as follows:

1 2 3 4 5
2 2 6 4 10
3 6 3 12 15
4 4 12 4 20
Looking at this table, Crash thought of a lot of questions to think about. But the problem he most wanted to solve was a very simple one: what is the sum of all the numbers in this table. When N and M are big, Crash can't do anything, so he finds a clever program to help him solve this problem. Since the final result can be very large, Crash just wants to know the sum of all the numbers in the table and the value of mod20101009.

Input and output format

Input format:
The first line of input contains two positive integers, representing N and M, respectively.

Output format:
output a positive integer representing the sum mod20101009 of all numbers in the table.

Input and output example

Input Sample #1: Copy
4 5
Output Sample #1: Copy
122
Description

30% of the data satisfy N, M≤ 10^3.

70% of the data satisfy N, M≤ 10^5.

100% of the data satisfy N, M≤ 10^7.

Analysis: There are some solutions in Luogu, which are quite detailed.
Note: The f[x] and g[x] set during inversion should set all the related terms with [gcd(i,j)==d], such as
f[x]=i*j in this question *[gcd(i,j)==d]
g[x]=i*j*[x|gcd(i,j)]

So f[x]=mul[x]*g[n/x]
finally knew how to ask for g under the guidance of dalao

Code:

#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long

const LL mod=20101009;
const LL maxn=10000007;

using namespace std;

LL ans;
LL not_prime[maxn],prime[maxn];
LL mul[maxn];
LL n,m,cnt;

void getmul(LL n)
{
    mul[1]=1;
    for (LL i=2;i<=n;i++)
    {
        if (!not_prime[i])
        {
            prime[++cnt]=i;
            mul[i]=-1;
        }
        for (LL j=1;j<=cnt;j++)
        {
            if (i*prime[j]>n) break;
            not_prime[i*prime[j]]=1;
            if (i%prime[j]==0)
            {
                mul[i*prime[j]]=0;
                break;
            }
            mul[i*prime[j]]=-mul[i];
        }
    }
    for (LL i=1;i<=n;i++) mul[i]=(mul[i-1]+(mul[i]*i*i)%mod)%mod;
}

LL getsum(LL l,LL r)
{
    return (l+r)*(r-l+1)%mod*10050505%mod;
} 

LL g(int n,int m)
{
    if (n>m) swap(n,m);
    LL ans=0,last=0;    
    for (LL i=1;i<=n;i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        ans=(ans+getsum(1,n/i)*getsum(1,m/i)%mod*(mul[last]-mul[i-1]+mod)%mod)%mod;
    }
    return ans;
}

int main()
{
    getmul(maxn);
    scanf("%lld%lld",&n,&m);
    if (n>m) swap(n,m);             
    for (LL i=1,last=0;i<=n;i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        ans=(ans+getsum(i,last)*g(n/i,m/i)%mod)%mod;
    }
    printf("%lld",ans);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324714695&siteId=291194637