您的位置:首页 > 其它

[BZOJ 2154] Crash的数字表格

2015-06-18 20:48 405 查看

2154: Crash的数字表格

Time Limit: 20 Sec Memory Limit: 259 MB
Submit: 1337 Solved: 531
[Submit][Status][Discuss]

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。

HINT

Source

数论

【题解】

用莫比乌斯繁衍(题解均省略取模运算)

设sum2(i)=i*(i+1)/2

设函数sum(i,j)=sum2(i)*sum2(j)

那么,ans=sigma (D=1 to min(n,m)) sum(n/d,m/d)* (sigma (i|D) Di*mu[i])

(这是可以推出来的)

然后呢,YSY聚聚告诉我了一个方法:

线性筛筛素数,记录i最小素数因子为mz[i]

然后,设f[D] 为 (sigma (i|D) Di*mu[i]),那么,

f[D]=f[D/mz[i]](mz[i/mz[i]]==mz[i])

f[D]=f[D/mz[i]]*(1-mz[i]) (else)

那么,即可在O(n)时间内处理

可以用前缀和维护f,则在O(sqrt n)之内处理完

需要强调的是!!!!!!!

括号啊括号!!long long啊long long!!!

WA了10几次,精度爆炸了

首先是sum,不能连乘3次!!

long long 强制转换要放内部!

唉,ysy一遍A,我WA了10几次,TAT

#include<bits/stdc++.h>
using namespace std;
int prime[1000010];
int tot,mz[10000010];
int f[10000010],n,m;
long long ans;
const int mod=20101009;
long long sum(int ki,int kj) {
return ((((long long)ki*(ki+1)/2)%mod)*(((long long)kj*(kj+1)/2)%mod))%mod;
}
int main() {
//freopen("a.out","w",stdout);
scanf("%d%d",&n,&m);
if (n>m) {
int t=n;
n=m;
m=t;
}
for (int i=2;i<=n;++i) {
if (!mz[i]) {
prime[++tot]=i;
mz[i]=i;
}
for (int j=1;j<=tot&&i*prime[j]<=n;++j) {
mz[i*prime[j]]=prime[j];
if(i%prime[j]==0) break;
}
}
//for (int i=1;i<=tot;++i) cout<<prime[i]<<endl;
//for (int i=1;i<=n;++i) cout<<mz[i]<<endl;
f[1]=1;
for (int i=2;i<=n;++i)
if(mz[i/mz[i]]==mz[i]) f[i]=f[i/mz[i]];
else f[i]=((long long)f[i/mz[i]]*(1-mz[i]))%mod;
for (int i=2;i<=n;++i)
f[i]=((long long)f[i]*i+f[i-1])%mod;
int j=0;
for (int i=1;i<=n;i=j+1) {
j=min(n/(n/i),m/(m/i));
ans=(ans+(sum(n/i,m/i)*(long long)(f[j]-f[i-1])%mod))%mod;
}
printf("%lld\n",(ans+mod)%mod);
return 0;
}


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