hdu 6588 题解
【题意】
求 \(\displaystyle \sum_{i=1}^n \gcd(\lfloor\sqrt[3] i\rfloor, i)\bmod 998244353, n\leq 10^{21}\)
【分析】
正面求解很难,考虑枚举 \(\lfloor\sqrt[3] i\rfloor\)
当 \(\lfloor\sqrt[3] i\rfloor\)=t$ 时 \(i\in [t^3, (t+1)^3-1]\)
故考虑枚举开三方的数字:
记 \(m=\lfloor\sqrt[3] n\rfloor\)
\(\displaystyle \sum_{i=1}^n \gcd(\lfloor\sqrt[3] i\rfloor, i)=\sum_{t=1}^{m-1} \sum_{i=t^3}^{(t+1)^3-1} \gcd(t, i)+\sum_{i=m^3}^n \gcd(m, i)\)
考虑到 \(\gcd(t, i+t)=\gcd(t, i+t-t)=\gcd(i, t)\)
因此每 \(t\) 个连续的 \(\gcd(t, i)\) 的求和都等于 \(\displaystyle \sum_{i=1}^t \gcd(i, t)\)
记 \(\displaystyle G_t(n)=\sum_{i=1}^n \gcd(i, t)\) 则 \(G_t(n)=(n/t)\cdot G_t(t)+G_t(n\bmod t)\)
因此 \(\displaystyle \sum_{i=t^3}^{(t+1)^3-1} \gcd(t, i)=G_t(t^3+3t^2+3t)-G_t(t^3)+\gcd(t^3, t)=(t^2+3t+3-t^2)G_t(t)+t=(3t+3)G_t(t)+t\)
而同理, \(\displaystyle \sum_{i=m^3}^n \gcd(m, i)=(n/m-m^2)G_m(m)+G_m(n\bmod m)+m\)
\(\begin{aligned} \therefore& \sum_{i=1}^n \gcd(\lfloor\sqrt[3] i\rfloor, i) \\\\=&\sum_{t=1}^{m-1} \sum_{i=t^3}^{(t+1)^3-1} \gcd(t, i)+\sum_{i=m^3}^n \gcd(m, i) \\\\=&\sum_{t=1}^{m-1} [(3t+3)G_t(t)+t]+(n/m-m^2)G_m(m)+m-G_m(n\bmod m) \end{aligned}\)
预处理 \(G_t(t)\) 极其前缀和,每次查询的时候就获取 \(m=\lfloor\sqrt[3] n\rfloor\) ,然后 \(O(1)\) 算出除 \(G_m(n\bmod m)\) 的部分
当然,由于 \(n\leq 10^{21}\) 可能涉及 __int128
,可能无法使用 pow()
函数。可以考虑二分 \(m\)
考虑剩下的部分 \(\displaystyle G_m(n\bmod m)=\sum_{i=1}^{n\bmod m}\gcd(i, m)\)
方便期间,记 \(\displaystyle g(n, m)=\sum_{i=1}^{n\bmod m}\gcd(i, m)\)
由莫比乌斯反演得:
\(\begin{aligned} g(n, m)&=\sum_{i=1}^n\gcd(i, m) \\\\&=\sum_{i=1}^n \sum_{d\mid i\wedge d\mid m}\boldsymbol \varphi(d)&\text{(欧拉反演)} \\\\&=\sum_{d\mid m}\boldsymbol \varphi(d)\sum_{i=1}^n [d\mid i] \\\\&=\sum_{d\mid m}\boldsymbol \varphi(d)(n/d) \end{aligned}\)
答案为 \(G_m(n\bmod m)=g(n\bmod m, m)\) ,直接预处理欧拉函数,然后 \(O(\sqrt m)\) 枚举因数即可
最后剩下 \(G_t(t)\) 没解决,等价于 \(\displaystyle g(t, t)=\sum_{d\mid t} \boldsymbol \varphi(d) ({t\over d})=(\boldsymbol \varphi*\boldsymbol {id})(t)\)
这个为两个积性函数的狄利克雷卷积,也为积性函数,为方便,记 \(\boldsymbol f=\boldsymbol \varphi*\boldsymbol {id}\)
考虑如何线筛得到:
\(\begin{aligned} \boldsymbol f(p^k)&=\sum_{i=1}^{k-1} \boldsymbol \varphi(p^i)\boldsymbol {id}(p^{k-i})+\boldsymbol \varphi(p^k)+\boldsymbol {id}(p^k)&(k>1) \\\\&=\sum_{i=1}^{k-1} (p^{i-1}(p-1)\cdot p^{k-i})+p^{k-1}(p-1)+p^k \\\\&=p^{k-1}(p-1)\cdot k+p^k \end{aligned}\)
则 \(\boldsymbol f(p^{k-1})=p^{k-2}(p-1)\cdot (k-1)+p^{k-1}\)
因而 \(p\cdot \boldsymbol f(p^{k-1})=p^{k-1}(p-1)\cdot (k-1)+p^k=\boldsymbol f(p^k)-p^{k-1}(p-1)=\boldsymbol f(p^k)-\boldsymbol \varphi(p^k)\)
因此 \(\boldsymbol f(p^k)=p\cdot \boldsymbol f(p^{k-1})+\boldsymbol \varphi(p^k)=p\cdot \left[\boldsymbol f(p^{k-1})+\boldsymbol \varphi(p^{k-1})\right]\)
记 \(fc_n\) 表示 \(n\) 的最小质因数, \(fck_n\) 表示 \(n\) 的最小质因子的指数,例如 \(fck_{12}=2^2\)
故当 \(p\neq fc_n\) 时 \(\boldsymbol f(n\cdot p)=\boldsymbol f(n)\cdot \boldsymbol f(p)=\boldsymbol f(n)\cdot (2p-1)\)
当 \(p=fc_n\) 时
\(\begin{aligned} &\boldsymbol f(n\cdot p) \\\\=&\boldsymbol f({n\over fck_n})\cdot \boldsymbol f(fck_n\cdot p) \\\\=&\boldsymbol f({n\over fck_n}) \cdot p\cdot \left[\boldsymbol f(fck_n)+\boldsymbol \varphi(fck_n)\right] \\\\=&p\cdot [\boldsymbol f(n)+\boldsymbol f({n\over fck_n})\cdot \boldsymbol \varphi(fck_n)] \end{aligned}\)
考虑线筛的时候,同时维护最小质因数 fc[i]
,最小质因子的指数 fck[i]
,欧拉函数 phi[i]
,以及该函数值 f[i]
即可直接转移
总复杂度 \(O(n+T(\log n+\sqrt n)\ )=O(n+T\sqrt n)\)
【代码】
只跑了 1.8s
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Lim=1e7, MAXN=Lim+10, P=998244353;
#define de(x) cout << #x << " = " << x << endl
#define dd(x) cout << #x << " = " << x << " "
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;
}
int fc[MAXN], prime[MAXN/10], cntprime, fck[MAXN], phi[MAXN], f[MAXN], sumit[MAXN];
inline void init() {
phi[1]=f[1]=1;
for(int i=2; i<=Lim; ++i) {
if(!fc[i]) {
fc[i]=prime[++cntprime]=fck[i]=i;
phi[i]=i-1;
f[i]=i+i-1;
}
for(int j=1; j<=cntprime; ++j)
if(prime[j]*i>Lim) break;
else if(prime[j]<fc[i]) {
fc[prime[j]*i]=prime[j];
fck[prime[j]*i]=prime[j];
phi[prime[j]*i]=phi[i]*(prime[j]-1);
f[prime[j]*i]=f[i]*(2ll*prime[j]-1)%P;
}
else{
fc[prime[j]*i]=prime[j];
fck[prime[j]*i]=prime[j]*fck[i];
phi[prime[j]*i]=phi[i]*prime[j];
f[prime[j]*i]=(f[i]+(ll)f[i/fck[i]]*phi[fck[i]])%P*prime[j]%P;
}
}
for(int i=1; i<=Lim; ++i)
sumit[i]=((3ll*i+3)*f[i]+i+sumit[i-1])%P;
}
inline int g(int n, int m) {
int res=0;
for(int i=1, j; i*i<=m; ++i) if(m%i==0) {
j=m/i;
res=(res+(ll)phi[i]*(n/i))%P;
if(i!=j) res=(res+(ll)phi[j]*(n/j))%P;
}
return res;
}
inline int findit(__int128 m) {
__int128 l=1, r=1e7, mid, ans=0;
while(l<=r) {
mid=l+r>>1;
if(mid*mid*mid<=m) {
ans=mid;
l=mid+1;
}
else r=mid-1;
}
return ans;
}
inline int ans(__int128 n) {
int m=findit(n);
int res=((n/m-(ll)m*m)*f[m]+m)%P+g(n%m, m);
res=(res%P+sumit[m-1])%P;
return res<0?res+P:res;
}
int main() {
init();
int t; read(t);
__int128 n;
while(t--) read(n), printf("%d\n", ans(n));
return 0;
}