Problem
tty的求助
TimeLimit:20Sec
MemoryLimit:256MB
Description
求∑n=1N∑m=1M∑k=0m−1⌊mnk+x⌋,其中x为实数。
输入仅有一行。
第一行仅有两个正整数N,M和一个实数x。
Output
输出共一行,由于结果过大,所以请输出上式对998244353取模的结果。
Sample Output
Explanation
当n=1,m=1时,sum=1
当n=1,m=2时,sum=1
当n=1,m=3时,sum=1
当n=2,m=1时,sum=1
当n=2,m=2时,sum=1
当n=2,m=3时,sum=2
所以答案是7
HINT
N,M≤5×105,0<x≤105,x精确到小数点后8位。
标签:莫比乌斯反演
Solution
Ans=n=1∑Nm=1∑Mk=0∑m−1⌊mnk+x⌋
对于最后一次求和:
k=0∑m−1⌊mnk+x⌋=k=0∑m−1⌊mnk−nk%m+x+nk%m⌋=k=0∑m−1⌊mnk%m+x+mnk−nk%m⌋=k=0∑m−1⌊mnk%m+x⌋+k=0∑m−1mnk−k=0∑m−1mnk%m
先考虑前一项:
设d=gcd(n,m),那么n⋅dm≡0modm。于是有n(k+dm)%m=nk%m+dnm%m=nk%m,即可知nk%m=n(k%dm)%m。
k=0∑m−1⌊mnk%m+x⌋=k=0∑m−1⌊mn(k%dm)%m+x⌋=dmmk=0∑dm−1⌊mn(k%dm)%m+x⌋=dk=0∑dm−1⌊mnk%m+x⌋=dk=0∑dm−1⌊mnk%m+x⌋
对于k取遍d0,dd,d2d,⋯,dm−d,nk的值依次为dn⋅0,dn⋅d,dn⋅2d,⋯,dn⋅(dm−1)d。由于dn与⌊dm⌋互质,所以dn⋅k%m一定取遍0,1,2,⋯,(dm−1),因而nk%m一定取遍0,d,2d,⋯,(dm−1)d。故而有
k=0∑m−1⌊mnk%m+x⌋=dk=0∑dm−1⌊mnk%m+x⌋=dk=0∑dm−1⌊mkd+x⌋=dk=0∑dm−1⌊mkd+x%m+x−x%m⌋=dk=0∑dm−1⌊mkd+x%m⌋+d⋅dm⋅mx−x%m
又发现0≤kd+x%m<2m⇒0≤⌊mkd+x%m⌋<2,故
k=0∑m−1⌊mnk%m+x⌋=dk=0∑dm−1⌊mkd+x%m⌋+d⋅dm⋅mx−x%m=d×(k=0∑dm−1[kd≥m−x%m]+dx−x%m)=d×(k=0∑dm−1[k≥⌈dm−x%m⌉]+dx−x%m)=d×(⌊dx%m⌋+⌊dx⌋−⌊dx%m⌋)=d⌊dx⌋
对于后两项:
k=0∑m−1mnk=2mn⋅m⋅(m−1)=2nm−nk=0∑m−1mnk%m=dk=0∑dm−1mkd=2m−d
将三项和前面两个求和连起来:
LetAnsSi=1+2+⋯+i=2i×(i+1),=n=1∑Nm=1∑M(d⌊dx⌋+2nm−n−m+d)=n=1∑Nm=1∑M(d⌊dx⌋+2d)+21SNSM−2MSN−2NSM=n=1∑Nm=1∑M(d⌊dx⌋+2d)+21SNSM−2MSN−2NSM
对前面的和式做莫比乌斯反演:
n=1∑Nm=1∑M(d⌊dx⌋+2d)=d=1∑min(N,M)(d⌊dx⌋+2d)i=1∑⌊dN⌋j=1∑⌊dM⌋[gcd(i,j)=1]=d=1∑min(N,M)(d⌊dx⌋+2d)i=1∑⌊dN⌋j=1∑⌊dM⌋t∣i,j∑μ(t)=d=1∑min(N,M)(d⌊dx⌋+2d)t=1∑min(⌊dN⌋,⌊dM⌋)μ(t)⌊tdN⌋⌊tdM⌋
直接枚举d数论分块即可,总时间复杂度约为O(2n−2n)。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <bits/stdc++.h> #define MAX_N 500000 #define MOD 998244353 #define inv2 499122177 using namespace std; typedef double dnt; typedef long long lnt; bool NotPri[MAX_N+5]; dnt x; int n, m, cnt, pri[MAX_N+5], mu[MAX_N+5]; void init() { mu[1] = 1; for (int i = 2; i <= MAX_N; i++) { if (!NotPri[i]) pri[cnt++] = i, mu[i] = -1; for (int j = 0; j < cnt; j++) { if (i*pri[j] > MAX_N) break; NotPri[i*pri[j]] = true; if (i%pri[j]) mu[i*pri[j]] = -mu[i]; else {mu[i*pri[j]] = 0; break;} } } for (int i = 2; i <= MAX_N; i++) mu[i] += mu[i-1]; } lnt calc(int n, int m) { lnt ret = 0LL; for (int l = 1, r; l <= min(n, m); l = r+1) r = min(n/(n/l), m/(m/l)), (ret += 1LL*(mu[r]-mu[l-1])*(n/l)%MOD*(m/l)%MOD) %= MOD; return ret; } int main() { scanf("%d%d%lf", &n, &m, &x), init(); lnt sn = 1LL*n*(n+1)/2%MOD, sm = 1LL*m*(m+1)/2%MOD; lnt ans = sn*sm%MOD-1LL*m*sn%MOD-1LL*n*sm%MOD; for (int d = 1; d <= min(n, m); d++) (ans += (2LL*d*(lnt)(x/d)+d)%MOD*calc(n/d, m/d)%MOD) %= MOD; return printf("%lld\n", (ans*inv2%MOD+MOD)%MOD), 0; }
|