今天是颓废的一天。。上午考试gg了,下午迷之困倦。。本着这个时候肝肝数学题往往有奇效的心态,
我去luogu里随便找了一道题。。然后竟然意外地弥补了一下我水弱无比的数论分块,神奇。
题解:这道题最难的就是sum(n/i * m/i *i*i)了吧。。然后这个东西我本来以为是O(n)的,但是后来想了一下,
考虑到每个n/i,m/i都是一段区间,看成4*sqrt(n)个端点在一条线段上分布,最多也只有4*sqrt(n)段,所以还是根号的。
学习了一下两个同时进行的数论分块,其实和一个的差别也不是很大。
#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (int x=y; x<=z; x++)
#define downrep(x,y,z) for (int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (int x=hed[y]; ~x; x=edge[x].nex)
inline LL read(){
LL x=0; int w=0; char ch=0;
while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return w? -x:x;
}
const LL P=19940417;
LL a[15];
LL sum1(LL l,LL r){
LL t1=l+r; LL t2=r-l+1;
if (t1&1) t2/=2; else t1/=2;
return ((t1%P)*(t2%P))%P;
}
LL sum2(LL n){
a[1]=n; a[2]=n+1; a[3]=2*n+1;
rep(i,1,3) if (!(a[i]&1)) { a[i]/=2; break; }
rep(i,1,3) if (!(a[i]%3)) { a[i]/=3; break; }
return (((((a[1]%P)*(a[2]%P))%P)*(a[3]%P))%P+P)%P;
}
LL sum(LL l,LL r){
return ((sum2(r)-sum2(l-1))%P+P)%P;
}
LL solve(LL n,LL R){
LL r=0; LL ans=0; R=min(n,R);
for(LL l=1; l<=R; l=r+1){
r=min(R,n/(n/l)); ans=(ans+sum1(l,r)*((n/l)%P))%P;
}
return (ans%P+P)%P;
}
LL calc(LL n,LL m,LL R){
LL r=0; LL ans=0; R=min(n,R); R=min(m,R);
for(LL l=1; l<=R; l=r+1){
r=min(R,n/(n/l)); r=min(r,m/(m/l));
ans=(ans+(((sum(l,r)*((n/l)%P))%P)*((m/l)%P))%P)%P;
}
return (ans%P+P)%P;
}
int main(){
LL n=read(); LL m=read();
LL ans=(((n%P)*(n%P))%P-solve(n,n))%P;
ans=(ans*((((m%P)*(m%P))%P-solve(m,m))%P))%P;
LL R=min(n,m); LL todec=(((((n%P)*(m%P))%P)*R)%P-(solve(n,R)*(m%P))%P-(solve(m,R)*(n%P))%P+calc(n,m,R))%P;
ans=(ans-todec)%P; ans=(ans%P+P)%P;
printf("%lld\n",ans);
return 0;
}