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
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); }