BZOJ 2693 jzptab 莫比乌斯反演 &&2154: 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 ≤ 10^7。

 

我们是能推出来这个公式的,这种情况的话我们是能预处理 i^2*u[i]的这个东西,对于sum()里面的东西我们是可以分块来做的,所以总的时间复杂度就是o(n) 对于o(n)的话这个问题是可以解决的但是要是多组数据的话o(n)的时间复杂度就不行了,那是后我们再优化这个东西,我们把D=d*i;

  然后我们发现后面的东西是个积性函数,对于积性函数的话我们是可以利用线性筛把这个东西预处理出来的,为什么后面的东西是积性函数。

现在证为什么为积性函数: 首先我们知道的东西是:若𝑓 𝑛 ,𝑔(𝑛)均为积性函数则ℎ (n) = 𝑓(n)  𝑔(𝑛)也是积性函数。

然后我们知道的东西就是积性函数的约数和也是积性函数(这个东西好像很明显,但是但是我蠢啊!) 具体细节请读者自己思考。

然后我们就可以用一个线性筛的方法然后把这个问题完美的解决。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=20101009;
const int N=1e7+4;
int vis[N],prime[N];
ll g[N];
ll cnt;
void Init()
{
    memset(vis,0,sizeof(vis));
    g[1] = 1;
    cnt = 0;
    for(int i=2; i<N; i++)
    {
        if(!vis[i])
        {
            prime[cnt++] = i;
            g[i]=(long long)(1-i)*(i);
            g[i]=g[i]%mod;
        }
        for(int j=0; j<cnt&&i*prime[j]<N; j++)
        {
            vis[i*prime[j]] = 1;
            if(i%prime[j]) g[i*prime[j]]=(g[i]*g[prime[j]])%mod;
            else
            {
                g[i*prime[j]]=(g[i]*prime[j])%mod;
                break;// 为何这个会break,因为是为了解决时间。但是有的读者会担心是不是以后i*prime[j]会不出现啊,我们可以想一下,i要么是和prime[j]相同的素数,这个时候我们可以break;除了这种情况i就是含有的因子和prime[j]相同,这个时候我们只是得到了i*prime[j]后面的所有的数都可以得到,我们可以用假设的方法。
            }
        }
    }
    for(int i=1;i<N;i++)
    {
        g[i]=(g[i-1]+g[i])%mod;
    }
}
ll result(ll x,ll y)
{
    return (((x*(x+1)/2)%mod)*((y*(y+1)/2)%mod))%mod;
}
void work(int n,int m)
{
    if(n>m) swap(n,m);
    int r;
    ll ans=0;
    for(int i=1;i<=n;i=r+1)
    {
        r=min(n/(n/i),m/(m/i));
        ans+=(result(n/i,m/i)*((g[r]-g[i-1]+mod)%mod))%mod;
        ans%=mod;
    }
    printf("%lld\n",(ans+mod)%mod);
}
int main()
{
    int n,m;
    Init();
    scanf("%d%d",&n,&m);
    work(n,m);
}

 

posted @ 2017-02-23 23:27  Heilce  阅读(211)  评论(0编辑  收藏  举报