您的位置:首页 > 其它

【BZOJ 2154】Crash的数字表格 (莫比乌斯+分块)

2016-08-30 15:57 477 查看

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。



  这题用了两次分块了~~ 好高级...不过还不是多组的呢~
  好吧我也还是看题解的,还不是很会推~~
  http://blog.csdn.net/regina8023/article/details/44243911
  
  

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
#define Mod 20101009
#define Maxn 10000010
#define LL long long

LL mu[Maxn],pri[Maxn],h[Maxn],pl;
bool q[Maxn];

LL mymin(LL x,LL y) {return x<y?x:y;}

void get_mu(LL mx)
{
pl=0;
memset(q,1,sizeof(q));
mu[1]=1;
for(LL i=2;i<=mx;i++)
{
if(q[i])
{
pri[++pl]=i;
mu[i]=-1;
}
for(LL j=1;j<=pl;j++)
{
if(i*pri[j]>mx) break;
q[i*pri[j]]=0;
if(i%pri[j]==0) mu[i*pri[j]]=0;
else mu[i*pri[j]]=-mu[i];
if(i%pri[j]==0) break;
}
}
h[1]=(mu[1]*1*1)%Mod;
for(LL i=2;i<=mx;i++) h[i]=(h[i-1]+mu[i]*i*i)%Mod;
}

LL get_g(LL x,LL y)
{
return ( ( ((x+1)*x/2)%Mod )*( ((y+1)*y/2)%Mod ) )%Mod;
}

LL get_f(LL n,LL m)
{
LL t;
if(n>m) t=n,n=m,m=t;

LL sq=(LL)ceil(sqrt((double)m));

LL ans=0;
for(LL i=1;i<=mymin(n,sq);i++)
{
ans=( ans+((mu[i]*i*i)%Mod)*get_g(n/i,m/i) )%Mod;
}
for(int i=sq+1;i<=n;)
{
int x=n/i,y=m/i;
int r1=n/x+1,r2=m/y+1;
if(r1>n+1) r1=n+1;
if(r2>n+1) r2=n+1;
int r=mymin(r1,r2);
ans=(ans+ ((h[r-1]+Mod-h[i-1])%Mod)*get_g(x,y) )%Mod;
i=r;
}
return ans;
}

LL get_ans(int n,int m)
{
LL ans=0;

LL sq=(LL)ceil(sqrt((double)m));
for(LL i=1;i<=mymin(sq,n);i++)
{
ans=(ans+i*get_f(n/i,m/i) )%Mod;
}

for(LL i=sq+1;i<=n;)
{
LL x=n/i,y=m/i;
LL r1=n/x+1,r2=m/y+1;
LL r=mymin(r1,r2);
if(r>m+1) r=m+1;
ans=( ans+(((r-i)*(i+r-1)/2)%Mod)*get_f(x,y) )%Mod;
i=r;
}
return ans;
}

int main()
{
int T;
T=1;

while(T--)
{
LL n,m,t;
scanf("%lld%lld",&n,&m);
if(n>m) t=n,n=m,m=t;
get_mu(m);

LL ans=get_ans(n,m);

printf("%lld\n",ans);
}
return 0;
}


[BZOJ2154]

2016-08-30 16:00:42
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: