P2260 [清华集训 2012] 模积和 - Description
给定正整数 \(n\) 和 \(m\),求
的值
\(1\le n,m\le 10^9\)。
P2260 [清华集训 2012] 模积和 - Solution
感觉有点无脑。
首先令 \(n\le m\)。
现在这坨东西是 \(O(n)\) 的。碰到下取整那当然是 imagine 一下数论分块啦
形如 \(\sum \lfloor x\rfloor \times k\) 是经典的,这里主要讲讲最后面那一坨,即
这个东西我们称之为 二维数论分块。类似一维地,存在类似的规律,即在一个块内 \(\lfloor \frac{n}{i} \rfloor \times \lfloor \frac{m}{i} \rfloor\) 相等。
此处为了使两个下取整的积相等,更新右端点时应比较两个下取整,看哪个离左端点距离近。
时间复杂度还是 \(O(\sqrt{n})\)。
这题还有个难点是 \(O(1)\) 算 \(\sum i^2\),但是这是个小学数学题,只挂个结论。
#include<bits/stdc++.h>
#define int long long
#define mod 19940417
using namespace std;
long long n,m,ans,ans1,sumn,summ,sumnm,qwqq;
inline void init_n(){int r=1;for(int l=1;l<=n;l=r+1){int now=n/l;r=n/now;sumn+=(l+r)*(r-l+1)/2%mod*now%mod;sumn%=mod;}return;
}
inline void init_m(){int r=1;for(int l=1;l<=m;l=r+1){int now=m/l;r=m/now;summ+=(l+r)*(r-l+1)/2%mod*now%mod;summ%=mod;}return;
}
int S(int n){return 1ll*n*(n+1)%mod*(n+n+1)%mod*3323403%mod;}
inline void get_sumnm(){int r=1;for(int l=1;l<=m;l=r+1){int now=m/l;r=m/now;if(r>=n){sumnm+=(l+n)*(n-l+1)/2%mod*now%mod;break;}sumnm+=(l+r)*(r-l+1)/2%mod*now%mod;sumnm%=mod;}return;
}
inline void qwq(){int r=1;for(int l=1;l<=n;l=r+1){int now=m/l;r=min(n/(n/l),m/(m/l));qwqq+=(n/l)*now%mod*(S(r)-S(l-1))%mod;qwqq%=mod;}return;
}
signed main(){cin>>n>>m;if(n>m){swap(n,m);}init_n();init_m();get_sumnm();qwq();ans=n*n%mod;ans-=sumn;ans=(ans%mod+mod)%mod;ans1=m*m%mod;ans1-=summ;ans1=(ans1%mod+mod)%mod;ans*=ans1;ans%=mod;ans-=n*n%mod*m%mod;ans=(ans%mod+mod)%mod;ans+=n%mod*sumnm%mod;ans%=mod;ans+=m*sumn%mod;ans%=mod;ans-=qwqq;ans=(ans%mod+mod)%mod;cout<<ans<<endl;return 0;
}