题目描述
题解
这题就是正儿八经的化(画)式(柿)子
首先计算
i=j
和
i≠j
的总和
ans1=∑i=1n∑j=1m(n mod i)∗(m mod j)
=∑i=1n∑j=1m(n−⌊ni⌋i)∗(m−⌊mj⌋j)
=∑i=1n∑j=1m(nm−n⌊mj⌋j−m⌊ni⌋i+⌊ni⌋i⌊mj⌋j)
=n2m2−n2∑j=1m⌊mj⌋j−m2∑i=1n⌊ni⌋i+∑i=1n⌊ni⌋i∑j=1m⌊mj⌋j
然后计算
i=j
的情况
令
Min=min(n,m)
ans2=∑i=1Min(n mod i)∗(m mod i)
=∑i=1Min(n−⌊ni⌋i)∗(m−⌊mi⌋i)
=∑i=1Min(nm−n⌊mi⌋i−m⌊ni⌋i+⌊ni⌋⌊mi⌋i2)
=nmMin−n∑i=1Min⌊mi⌋i−m∑i=1Min⌊ni⌋i+∑i=1Min⌊ni⌋⌊mi⌋i2
最后就是
ans=ans1−ans2
形如
∑i=1n⌊mi⌋i
的式子可以分块
O(n√)
来做,用到等差数列的求和公式
形如
∑i=1N⌊ni⌋⌊mi⌋i2
的式子可以分块
O(n√+m−−√)
来做,用到平方数列的求和公式,其中二次方
∑i=1ni2=n(n+1)(2n+1)6
为什么叫做“膜”积和呢
因为代码写起来“膜”真 · tm多啊
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define Mod 19940417
#define inv 3323403
LL n,m,Min,ans1,ans2,ans;
LL s(LL n)
{
LL ans=n*(2*n%Mod+1)%Mod*(n+1)%Mod*inv%Mod;
return ans;
}
LL calc(LL n,LL k)
{
LL ans=0;
for (LL i=1,j=0;i<=n;i=j+1)
{
j=min(k/(k/i),n);
ans+=(k/i)*(j-i+1)*(i+j)/2;
ans%=Mod;
}
return ans;
}
LL CALC(LL N,LL n,LL m)
{
LL ans=0;
for (LL i=1,j=0;i<=N;i=j+1)
{
j=min(n/(n/i),m/(m/i));j=min(j,N);
ans+=(n/i)%Mod*(m/i)%Mod*(s(j)-s(i-1))%Mod;
ans%=Mod;
}
return ans;
}
int main()
{
scanf("%lld%lld",&n,&m);
ans1=n%Mod*n%Mod*m%Mod*m%Mod-n%Mod*n%Mod*calc(m,m)%Mod-m%Mod*m%Mod*calc(n,n)+calc(n,n)*calc(m,m)%Mod;
ans1=(ans1%Mod+Mod)%Mod;
Min=min(n,m);
ans2=n%Mod*m%Mod*Min%Mod-n%Mod*calc(Min,m)%Mod-m%Mod*calc(Min,n)%Mod+CALC(Min,n,m);
ans2=(ans2%Mod+Mod)%Mod;
ans=(ans1-ans2+Mod)%Mod;
printf("%lld\n",ans);
}