给出n,m,求
看到题目,题意十分简洁,心里十分舒畅。
看到 ni 就要想到 ni=n−⌊ni⌋∗i ,然后 ⌊ni⌋ 是可以用分块做的,下面再讲。
我们上面的式子可以转化为
我们想有一段区间[l,r], ⌊nl⌋=⌊nr⌋ ,因为r要求是满足这个条件最大的值,那么就是说 ⌊nl⌋<=nr ,那么就是 r<=⌊n⌊nl⌋⌋ ,因为r是整数,所以还要取整。那么就是[l,r]之间都是满足这个条件的,那么这段区间的答案就可以根据乘法分配律之类的,用 ⌊nl⌋ 乘上这段和或者是一些东西就可以了。长练分块打法好,危难来时把命保。
对于mod 19940417的逆元是3323403
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
const int mo=19940417;
const int ni6=3323403;
using namespace std;
ll i,j,k,l,t,n,m,ans,r,k1;
ll sum(ll x,ll y){
return ((y-x+1)*(y+x)/2)%mo;
}
ll qiuhe(ll x,ll y){
return ((x+y)*(y-x+1)/2)%mo;
}
ll suan(ll x){
ll t=0;
for(ll l=1,r;l<=x;l=r+1){
r=x/(x/l);
ll o=x/l;
t=(t+(r-l+1)*x%mo-qiuhe(l,r)*o%mo+mo)%mo;
}
return t;
}
ll pingfanghe(ll x){
ll t=0;
t=x*(x+1)%mo*(2*x+1)%mo*ni6%mo;
return t;
}
int main(){
scanf("%lld%lld",&n,&m);
if(n>m)swap(n,m);
ans=suan(n)*suan(m)%mo;
for(l=1;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ll p=n/l,q=m/l;
ans=(ans-n*m%mo*(r-l+1)%mo+mo)%mo;
ans=(ans-(pingfanghe(r)-pingfanghe(l-1)+mo)%mo*p%mo*q%mo)%mo;
ans=(ans+qiuhe(l,r)*(m*p%mo+n*q%mo)%mo+mo)%mo;
}
ans=(ans%mo+mo)%mo;
printf("%lld\n",ans);
}