bzoj2154 Crash的数字表格 莫比乌斯反演

Description

今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数。例如,LCM(6, 8) = 24。回到家后,Crash还在想着课上学的东西,为了研究最小公倍数,他画了一张N*M的表格。每个格子里写了一个数字,其中第i行第j列的那个格子里写着数为LCM(i, j)。一个4*5的表格如下: 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 ≤ 107。
 
http://blog.csdn.net/outer_form/article/details/50593188
 
 1 #include<cstring>
 2 #include<cmath>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cstdio>
 6 
 7 #define ll long long
 8 #define N 10000007
 9 #define mod 20101009
10 using namespace std;
11 inline int read()
12 {
13     int x=0,f=1;char ch=getchar();
14     while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
15     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
16     return x*f;
17 }
18 
19 ll n,m,ans;
20 ll sm[N];
21 int tot,mu[N],pri[N];
22 bool flag[N];
23 
24 ll sum(ll x,ll y)
25 {
26     return ((x*(x+1)/2)%mod)*((y*(y+1)/2)%mod)%mod;
27 }
28 void init_mu()
29 {
30     mu[1]=1;
31     for (int i=2;i<=min(n,m);i++)
32     {
33         if (!flag[i])pri[++tot]=i,mu[i]=-1;
34         for (int j=1;j<=tot&&(ll)pri[j]*i<=min(n,m);j++)
35         {
36             flag[pri[j]*i]=1,mu[pri[j]*i]=-mu[i];
37             if (i%pri[j]==0){mu[pri[j]*i]=0;break;}
38         }
39     }
40     for (ll i=1;i<=min(n,m);i++)
41         sm[i]=(sm[i-1]+(i*i*mu[i])%mod)%mod;
42 }
43 ll F(ll x,ll y)
44 {
45     ll ans=0,ps;
46     for (ll i=1;i<=min(x,y);i=ps+1)
47     {
48         ps=min(x/(x/i),y/(y/i));
49         ans=(ans+(sm[ps]-sm[i-1])%mod*sum(x/i,y/i)%mod)%mod;
50     }
51     return ans;
52 }
53 int main()
54 {
55     n=read(),m=read();
56     init_mu();
57     ll ps=0;
58     for (ll i=1;i<=min(n,m);i=ps+1)
59     {
60         ps=min(n/(n/i),m/(m/i));
61         ans=(ans+(i+ps)*(ps-i+1)/2%mod*F(n/i,m/i)%mod)%mod;
62     }
63     ans=(ans%mod+mod)%mod;
64     printf("%lld
",ans);
65 }

题目大意就是求ni=1mj=1lcm(i,j)
分析:

ans=i=1nj=1mlcm(i,j)=i=1nj=1mijgcd(i,j)


枚举d=gcd(i,j),

f(n,m,k)=1<=i<=n1<=j<=mgcd(i,j)=kij


显然可以得到 

ans=d=1min(n,,m)d2f(nd,md,1)d=d=1min(n,,m)df(nd,md,1)


即算出除以d后互质的对数,两个数都乘d的乘积就得到了两个数的乘积,在除以d就是他们的最小公倍数。 
那怎么求f呢 

sum(x,y)=1<=i<=x1<=j<=yij=x(x+1)2y(y+1)2
F(x,y,k)=1<=i<=x1<=j<=yk|gcd(i,j)ij=k2sum(nkmk)=k|df(i,j,d)
f(x,y,k)=k|dμ(dk)F(x,y,d)


所以

f(x,y,1)=k=1min(m,n)μ(k)F(x,y,k)=k=1min(x,y)μ(k)k2sum(xkyk)=k=1min(x,y)μ(k)k2xk(xk+1)2yk(yk+1)2
原文地址:https://www.cnblogs.com/fengzhiyuan/p/8185092.html