题意
N,M<=500000,0<x<=100000
N
,
M
<=
500000
,
0
<
x
<=
100000
,x 精确到小数点后8位。
分析
大力推式子题,一开始想像类欧那样推发现并没有什么用。
考虑如果n个m都固定了,那么我们要求的就是
∑k=0m−1⌊nk+xm⌋
∑
k
=
0
m
−
1
⌊
n
k
+
x
m
⌋
=∑k=0m−1⌊nkmodm+xm⌋+nk−nkmodmm
=
∑
k
=
0
m
−
1
⌊
n
k
mod
m
+
x
m
⌋
+
n
k
−
n
k
mod
m
m
先一项一项考虑,设 d=gcd(n,m) d = g c d ( n , m ) ,不难发现 nkmodm n k mod m 存在长度为 md m d 的周期,那么
∑k=0m−1⌊nkmodm+xm⌋
∑
k
=
0
m
−
1
⌊
n
k
mod
m
+
x
m
⌋
=d∑k=0md−1⌊kd+xm⌋
=
d
∑
k
=
0
m
d
−
1
⌊
k
d
+
x
m
⌋
=d(∑k=0md−1⌊kd+xmodmm⌋+x−xmodmm)
=
d
(
∑
k
=
0
m
d
−
1
⌊
k
d
+
x
mod
m
m
⌋
+
x
−
x
mod
m
m
)
=d(⌊xmodmd⌋+x−xmodmd)
=
d
(
⌊
x
mod
m
d
⌋
+
x
−
x
mod
m
d
)
=d⌊xd⌋
=
d
⌊
x
d
⌋
再考虑后面那项
∑k=0m−1nk−nkmodmm
∑
k
=
0
m
−
1
n
k
−
n
k
mod
m
m
=n(m−1)2−d∑k=0md−1kdm
=
n
(
m
−
1
)
2
−
d
∑
k
=
0
m
d
−
1
k
d
m
=n(m−1)−m+d2
=
n
(
m
−
1
)
−
m
+
d
2
那么答案就是
∑n=1N∑m=1Md⌊xd⌋+n(m−1)−m+d2
∑
n
=
1
N
∑
m
=
1
M
d
⌊
x
d
⌋
+
n
(
m
−
1
)
−
m
+
d
2
这个只要反演一下然后调和级数复杂度算一下即可。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int N=500005;
const int MOD=998244353;
int n,m,x,f[N],mu[N],tot,prime[N];
bool not_prime[N];
void get_prime(int n)
{
mu[1]=1;
for (int i=2;i<=n;i++)
{
if (!not_prime[i]) prime[++tot]=i,mu[i]=-1;
for (int j=1;j<=tot&&i*prime[j]<=n;j++)
{
not_prime[i*prime[j]]=-1;
if (i%prime[j]==0) break;
mu[i*prime[j]]=-mu[i];
}
}
}
int main()
{
double r;scanf("%d%d%lf",&n,&m,&r);
x=(int)r;
get_prime(n);
int ny2=MOD-MOD/2;
int ans=(LL)((LL)n*(n+1)%MOD*ny2%MOD*m%MOD*(m-1)%MOD*ny2%MOD-(LL)n*m%MOD*(m+1)%MOD*ny2%MOD)*ny2%MOD;
for (int d=1;d<=n;d++)
{
int s=0;
for (int i=d;i<=n;i+=d) (s+=(LL)(n/i)*(m/i)%MOD*mu[i/d])%=MOD;
(ans+=((LL)s*d%MOD*(x/d)%MOD+(LL)s*d%MOD*ny2%MOD)%MOD)%=MOD;
}
printf("%d",(ans+MOD)%MOD);
return 0;
}