HYSBZ/BZOJ 2154 Crash的数字表格 - 莫比乌斯反演

题目描述

由于不想码推导过程,粘一个by Liu Junhao

最开始推到最后的式子,却傻傻的没有意识到可以分块加速,还以为自己推错了。。=_= 表示以后看到向下取整的东东要注意了。
注意:Mod要写就写完,不要懒,谁知道会不会爆??。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 10000000
#define MAXP 700000
#define Mod 20101009LL

int n,m,mu[MAXN+10],prime[MAXP+10],cntpr;
bool isprime[MAXN+10];
long long sum[MAXN+10];

void GetMobius(int n)
{
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!isprime[i]){
            prime[++cntpr]=i;
            mu[i]=-1;
        }
        for(int j=1;prime[j]*i<=n&&j<=cntpr;j++){
            isprime[prime[j]*i]=true;
            if(i%prime[j]==0){
                mu[prime[j]*i]=0;
                break;
            }
            mu[prime[j]*i]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)
        sum[i]=(1LL*mu[i]*i*i%Mod+sum[i-1])%Mod;
}
long long Cal(int n)
{
    return 1LL*(n+1)*n/2%Mod;
}
long long F(int x,int y)
{
    long long ret=0;
    int side=min(x,y),last;
    for(int t=1;t<=side;t=last+1){
        last=min(x/(x/t),y /(y /t));
        ret=(ret+((sum[last]-sum[t-1])*(Cal(x/t)*Cal(y /t)%Mod))%Mod)%Mod;
    }
    return ret;
}
int main()
{
    scanf("%d%d",&n,&m);
    GetMobius(max(n,m));
    int side=min(n,m),last;
    long long ans=0;
    for(int i=1;i<=side;i=last+1){
        last=min(n/(n/i),m /(m / i));
        ans=(ans+1LL*(last+i)*(last-i+1)/2%Mod*F(n/i,m / i)%Mod)%Mod;
    }
    printf("%lld\n",(ans+Mod)%Mod);
}
posted @ 2016-01-27 21:18  KatarinaYuan  阅读(174)  评论(0编辑  收藏  举报