P2260 [清华集训2012]模积和
显然式子可以变成:
然后发现两个部分差不多,就是余数求和,传送门
但是有限制 i ≠ j
所以特殊考虑 i=j 时的答案,减去就好了
当 i = j 时的答案
然后展开一波可以得到:
= $n\times m\times min(n,m) - \sum _{i=1}^{min(n,m)}\times i\times n\times \left \lfloor \frac{m}{i} \right \rfloor - \sum _{i=1}^{min(n,m)}\times i\times m\times \left \lfloor \frac{n}{i} \right \rfloor + \sum _{i=1}^{min(n,m)}\times i^2\times \left \lfloor \frac{n}{i} \right \rfloor\times \left \lfloor \frac{m}{i} \right \rfloor$
然后可以像余数求和一样吧 $\left \lfloor \frac{n}{i} \right \rfloor$ 和 $\left \lfloor \frac{m}{i} \right \rfloor$ 相同的区间放在一起算
有一个公式:
注意:模数不是质数!
所以要先求出 6 的逆元
在代码里搞好麻烦啊,然后就另外打了一个暴力:
枚举所有 i 找到第一个 6i % 19940417 = 1 的值....
找到了就直接把 6 的逆元放到代码里当常数用..
提醒一下 [n/i] 不用逆元
然后就是代码了
#include<iostream> #include<cstdio> #include<cmath> using namespace std; typedef long long LL; const int crk=19940417;//%%%crk dalao const int inv_6=3323403;//6在膜crk下的逆元2333 LL n,m,ans; inline LL f1(LL l,LL r){ return (l+r)*(r-l+1)/2; }// 求∑ l+ l+1 + ... + r inline LL f2(LL p){ return p*(p+1)%crk *(2*p+1)%crk *inv_6%crk; }// 求∑ 1^2 + 2^2 + ... + p^2 inline LL slove(LL x)//先求出不考虑i=j时的答案 { LL res=0; int j; for(int i=1;i<=x;i=j+1) { j=x/(x/i); res+=x/i*f1(i,j); } return res; } inline LL Slove(LL x,LL y)//减去i=j时的情况 { int j,l=min(x,y); LL res=n*m%crk*l%crk; for(int i=1;i<=l;i=j+1) { j=min( x/(x/i) , y/(y/i) ); res=(res+ (crk- (x/i)*f1(i,j) %crk *y%crk) ) %crk; res=(res+ (crk- (y/i)*f1(i,j) %crk *x%crk) ) %crk; res=(res+ (f2(j)-f2(i-1)+crk) %crk * (x/i)%crk * (y/i)%crk )%crk; } return res; } int main() { cin>>n>>m; ans= ( (n*n-slove(n)) %crk)*( (m*m-slove(m)) %crk) %crk; ans= (ans-Slove(n,m)+crk) %crk; cout<<ans; return 0; }