2019杭电多校一 K. Function (数论)
大意: 给定$n(n\le 10^{21})$, 求$\sum\limits_{i=1}^n gcd(\lfloor\sqrt[3]{i}\rfloor,i)\mod 998244353$
首先立方根可以分块, 转化为
$\sum\limits_{i=1}^{\lfloor\sqrt[3]{n}\rfloor}\sum\limits_{j=i^3}^{min(n,(i+1)^3-1)}gcd(i,j)=\sum\limits_{i=\lfloor\sqrt[3]{n}\rfloor^3}^ngcd(r+1,i)+\sum\limits_{i=1}^r\sum\limits_{j=i^3}^{(i+1)^3-1}gcd(i,j)$
然后有$\sum\limits_{i=1}^n gcd(S,i)=\sum\limits_{d|S}\lfloor\frac{n}{d}\rfloor\varphi(d)$, 所以可以得到
$\begin{align}\sum\limits_{i=1}^r\sum\limits_{j=i^3}^{(i+1)^3-1}gcd(i,j) &=\sum\limits_{i=1}^r\sum\limits_{d|i}(\lfloor\frac{(i+1)^3-1}{d}\rfloor-\lfloor\frac{i^3-1}{d}\rfloor)\varphi(d) \notag \\ &= \sum\limits_{d=1}^r\sum\limits_{i=1}^{\lfloor\frac{r}{d}\rfloor}(\lfloor\frac{(di+1)^3-1}{d}\rfloor-\lfloor\frac{(di)^3-1}{d}\rfloor) \notag \\ &= \sum\limits_{d=1}^r\varphi(d)\sum\limits_{i=1}^{\lfloor\frac{r}{d}\rfloor}(3di^2+3i+1)\notag\end{align}$
可以$O(\sqrt[3]{n})$求出.
#include <iostream> #include <cmath> #include <cstdio> #define REP(i,a,n) for(int i=a;i<=n;++i) using namespace std; typedef long long ll; typedef __int128 i128; template <class T> void read(T &x) { static char ch;static bool neg; for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar()); for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar()); x=neg?-x:x; } const int P = 998244353, N = 1e7+10; int phi[N], p[N], cnt, vis[N]; void init() { phi[1] = 1; for (int i=2; i<N; ++i) { if (!vis[i]) p[++cnt]=i,phi[i]=i-1; for (int j=1,t; j<=cnt&&i*p[j]<N; ++j) { vis[t=i*p[j]] = 1; if (i%p[j]==0) {phi[t]=phi[i]*p[j];break;} phi[t]=phi[i]*phi[p[j]]; } } } int gcd(int x, int y) {return y?gcd(y,x%y):x;} int S_0(int x) {return x;} int S_1(int x) {return (ll)x*(x+1)/2%P;} int S_2(int x) {return (ll)x*(x+1)%(6ll*P)*(2*x+1)/6%P;} int calc(int s, i128 l, i128 r) { int ans = 0, mx = sqrt(s+0.5); --l; REP(d,1,mx) if (s%d==0) { ans = (ans+(r/d-l/d)*phi[d])%P; int t = s/d; if (t!=d) ans = (ans+(r/t-l/t)*phi[t])%P; } return ans; } int main() { init(); int t; scanf("%d", &t); while (t--) { i128 n; read(n); int r = 0; while ((i128)(r+2)*(r+2)*(r+2)-1<=n) ++r; int ans = calc(r+1,(i128)(r+1)*(r+1)*(r+1),n); REP(d,1,r) { int ret = (S_0(r/d)+3ll*S_1(r/d)+3ll*d*S_2(r/d))%P; ans = (ans+(ll)ret*phi[d])%P; } if (ans<0) ans += P; printf("%d\n", ans); } }