题目链接:模积和
这种有模运算的题一般都要把取模运算给去掉,改成除法取下整的模式。即(amod b=a-lfloor frac{a}{b} floor b)
然后我们先把(i=j)的也统计进答案,最后再减去即可。接下来就是推式子时间((n le m)):
egin{aligned}
&sum_{i=1}^nsum_{j=1}^m(n mod i)(m mod j) \
=&sum_{i=1}^n(n mod i)sum_{j=1}^m(m mod j) \
=&sum_{i=1}^n(n-ilfloor frac{n}{i}
floor)sum_{j=1}^m(m-jlfloor frac{m}{j}
floor) \
=&(n^2-sum_{i=1}^nilfloor frac{n}{i}
floor)(m^2-sum_{i=1}^milfloor frac{m}{i}
floor)
end{aligned}
egin{aligned}
&sum_{i=1}^n(n mod i)(m mod i) \
=&sum_{i=1}^n(n-ilfloor frac{n}{i}
floor)(m-ilfloor frac{m}{i}
floor) \
=&n^2m-msum_{i=1}^nilfloor frac{n}{i}
floor-nsum_{i=1}^nilfloor frac{m}{i}
floor+sum_{i=1}^nlfloor frac{n}{i}
floorlfloor frac{m}{i}
floor i^2
end{aligned}
然后分块计算即可。上下两个式子一减就是答案。
下面贴代码:
#include<cstdio> #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define mod 19940417 #define llg long long #define min(a,b) (a<b?a:b) const int n6=7776; int n,m,a[3]; llg S(int x){return (1ll*x*(x+1)>>1)%mod;} llg S2(int x){ a[0]=x,a[1]=x+1,a[2]=2*x+1; for(int i=0;i<3;i++) if(a[i]%2==0){a[i]/=2;break;} for(int i=0;i<3;i++) if(a[i]%3==0){a[i]/=3;break;} return 1ll*a[0]*a[1]%mod*a[2]%mod; } llg work(int x,int y){ llg now=0; for(int i=1,nt;i<=x;i=nt+1) nt=min(y/(y/i),x),now+=1ll*(y/i)*(S(nt)-S(i-1)); return now%mod; } int main(){ File("a"); scanf("%d %d",&n,&m); if(n>m) n^=m^=n^=m; llg s1=work(n,n),ans; ans=(1ll*n*n-s1)%mod*(1ll*m*m%mod-work(m,m))%mod; ans+=s1*m+work(n,m)*n; ans%=mod; ans-=1ll*n*n%mod*m; ans%=mod; for(int i=1,nt;i<=n;i=nt+1){ nt=min(n/(n/i),m/(m/i)); ans-=(S2(nt)-S2(i-1))*(m/i)%mod*(n/i); ans%=mod; } printf("%lld",(ans+mod)%mod); return 0; }