背景:
又来刷水题了。
题目传送门:
https://www.luogu.org/problem/P2260
https://www.luogu.org/problem/P2834
题意:
求
∑
i
=
1
n
∑
j
=
1
,
j
≠
i
m
(
n
m
o
d
  
i
)
(
m
m
o
d
  
j
)
\sum_{i=1}^{n}\sum_{j=1,j≠i}^{m}(n\mod i)(m \mod j)
∑i=1n∑j=1,j̸=im(nmodi)(mmodj)
思路:
∑ i = 1 n ∑ j = 1 , j ≠ i m ( n m o d    i ) ( m o d    j ) \sum_{i=1}^{n}\sum_{j=1,j≠i}^{m}(n\mod i)(\mod j) i=1∑nj=1,j̸=i∑m(nmodi)(modj)
= ∑ i = 1 n ∑ j = 1 m ( n m o d    i ) ( m m o d    j ) − ∑ i = 1 min ( n , m ) ( n m o d    i ) ( m m o d    i ) =\sum_{i=1}^{n}\sum_{j=1}^{m}(n\mod i)(m\mod j)-\sum_{i=1}^{\min(n,m)}(n\mod i)(m\mod i) =i=1∑nj=1∑m(nmodi)(mmodj)−i=1∑min(n,m)(nmodi)(mmodi)
= ∑ i = 1 n ( n m o d    i ) ∑ j = 1 m ( m m o d    j ) − ∑ i = 1 min ( n , m ) ( n m o d    i ) ( m m o d    i ) =\sum_{i=1}^{n}(n\mod i)\sum_{j=1}^{m}(m\mod j)-\sum_{i=1}^{\min(n,m)}(n\mod i)(m\mod i) =i=1∑n(nmodi)j=1∑m(mmodj)−i=1∑min(n,m)(nmodi)(mmodi)
我们定义:
f
n
=
∑
i
=
1
n
(
n
m
o
d
  
i
)
f_n=\sum_{i=1}^{n}(n\mod i)
fn=∑i=1n(nmodi)
f
m
=
∑
i
=
1
m
(
m
m
o
d
  
i
)
f_m=\sum_{i=1}^{m}(m\mod i)
fm=∑i=1m(mmodi)
F
min
(
n
,
m
)
=
∑
i
=
1
min
(
n
,
m
)
(
n
m
o
d
  
i
)
(
m
m
o
d
  
i
)
F_{\min(n,m)}=\sum_{i=1}^{\min(n,m)}(n\mod i)(m\mod i)
Fmin(n,m)=∑i=1min(n,m)(nmodi)(mmodi),则:
a
n
s
=
f
n
f
m
−
F
min
(
n
,
m
)
ans=f_nf_m-F_{\min(n,m)}
ans=fnfm−Fmin(n,m)
考虑:
f
n
=
∑
i
=
1
n
(
n
m
o
d
  
i
)
=
∑
i
=
1
n
n
−
⌊
n
i
⌋
i
=
n
2
−
∑
i
=
1
n
⌊
n
i
⌋
i
\begin{aligned}f_{n}&=\sum_{i=1}^{n}(n\mod i)\\ &=\sum_{i=1}^{n}n-\lfloor \frac{n}{i}\rfloor i\\ &=n^2-\sum_{i=1}^{n}\lfloor \frac{n}{i}\rfloor i\end{aligned}
fn=i=1∑n(nmodi)=i=1∑nn−⌊in⌋i=n2−i=1∑n⌊in⌋i
就可以整除分块。
考虑:
F
min
(
n
,
m
)
=
∑
i
=
1
min
(
n
,
m
)
(
n
m
o
d
  
i
)
(
m
m
o
d
  
i
)
=
∑
i
=
1
min
(
n
,
m
)
(
n
−
⌊
n
i
⌋
i
)
(
m
−
⌊
m
i
⌋
i
)
=
∑
i
=
1
min
(
n
,
m
)
n
m
−
i
(
m
⌊
n
i
⌋
+
n
⌊
m
i
⌋
)
+
i
2
⌊
n
i
⌋
⌊
m
i
⌋
=
n
m
⋅
min
(
n
,
m
)
⋅
∑
i
=
1
min
(
n
,
m
)
−
i
(
m
⌊
n
i
⌋
+
n
⌊
m
i
⌋
)
+
i
2
⌊
n
i
⌋
⌊
m
i
⌋
\begin{aligned}F_{\min(n,m)}&=\sum_{i=1}^{\min(n,m)}(n\mod i)(m\mod i)\\ &=\sum_{i=1}^{\min(n,m)}(n-\lfloor \frac{n}{i}\rfloor i)(m-\lfloor \frac{m}{i}\rfloor i)\\ &=\sum_{i=1}^{\min(n,m)}nm-i(m\lfloor \frac{n}{i}\rfloor+n\lfloor \frac{m}{i}\rfloor)+i^2\lfloor \frac{n}{i}\rfloor\lfloor \frac{m}{i}\rfloor\\ &=nm\cdot \min(n,m)\cdot \sum_{i=1}^{\min(n,m)}-i(m\lfloor \frac{n}{i}\rfloor+n\lfloor \frac{m}{i}\rfloor)+i^2\lfloor \frac{n}{i}\rfloor\lfloor \frac{m}{i}\rfloor\end{aligned}
Fmin(n,m)=i=1∑min(n,m)(nmodi)(mmodi)=i=1∑min(n,m)(n−⌊in⌋i)(m−⌊im⌋i)=i=1∑min(n,m)nm−i(m⌊in⌋+n⌊im⌋)+i2⌊in⌋⌊im⌋=nm⋅min(n,m)⋅i=1∑min(n,m)−i(m⌊in⌋+n⌊im⌋)+i2⌊in⌋⌊im⌋
就可以整除分块了。
∑
i
=
1
n
i
2
=
(
n
)
(
n
+
1
)
(
2
n
+
1
)
6
\sum_{i=1}^{n}i^2=\frac{(n)(n+1)(2n+1)}{6}
∑i=1ni2=6(n)(n+1)(2n+1),而
m
o
d
  
∉
p
r
i
m
e
\mod ∉prime
mod∈/prime,因此不能费马小定理求逆元,我就离线暴力求了,你可以扩欧。
P2260 \text{P2260} P2260代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define mod 19940417
#define inv6 3323403
using namespace std;
LL n,m;
LL work1(LL x,LL y)
{
return ((x+y)*(y-x+1)/2)%mod;
}
LL work_pow(LL x)
{
return x*(x+1)%mod*((2ll*x+1)%mod)%mod*inv6%mod;
}
LL work2(LL x,LL y)
{
return (work_pow(y)-work_pow(x-1)+mod)%mod;
}
LL calc(LL n)
{
LL sum=0;
for(LL l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
sum=(sum+(n/l)*work1(l,r)%mod)%mod;
}
return (n*n%mod-sum+mod)%mod;
}
LL Calc(LL n,LL m)
{
LL sum=0;
for(int l=1,r;l<=min(n,m);l=r+1)
{
r=min(n/(n/l),m/(m/l));
sum=(sum-work1(l,r)*((m*(n/l)+n*(m/l))%mod)%mod+work2(l,r)*(n/l)%mod*(m/l)%mod+mod)%mod;
}
return (n*m%mod*min(n,m)%mod+sum)%mod;
}
int main()
{
scanf("%lld %lld",&n,&m);
printf("%lld",(calc(n)*calc(m)%mod-Calc(n,m)+mod)%mod);
}
P2834 \text{P2834} P2834代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define mod 1000000007
#define inv6 166666668
using namespace std;
LL n,m;
LL work1(LL x,LL y)
{
return ((x+y)*(y-x+1)/2)%mod;
}
LL work_pow(LL x)
{
return x*(x+1)%mod*((2ll*x+1)%mod)%mod*inv6%mod;
}
LL work2(LL x,LL y)
{
return (work_pow(y)-work_pow(x-1)+mod)%mod;
}
LL calc(LL n)
{
LL sum=0;
for(LL l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
sum=(sum+(n/l)*work1(l,r)%mod)%mod;
}
return (n*n%mod-sum+mod)%mod;
}
LL Calc(LL n,LL m)
{
LL sum=0;
for(int l=1,r;l<=min(n,m);l=r+1)
{
r=min(n/(n/l),m/(m/l));
sum=(sum-work1(l,r)*((m*(n/l)+n*(m/l))%mod)%mod+work2(l,r)*(n/l)%mod*(m/l)%mod+mod)%mod;
}
return (n*m%mod*min(n,m)%mod+sum)%mod;
}
int main()
{
scanf("%lld %lld",&n,&m);
printf("%lld",(calc(n)*calc(m)%mod-Calc(n,m)+mod)%mod);
}