题目
题意:求
1
,
2
,
3
,
4...
n
1,2,3,4...n
1,2,3,4...n中有多少个子序列是等比数列,
n
<
=
5
e
17
n<=5e17
n<=5e17
题解:
首先长度为1,2的等比数列我们可以直接算出答案。
对于长度>3的等比数列,
设公比
q
=
a
b
q = \frac ab
q=ba,那么最后一项被
a
l
e
n
g
t
h
−
1
a^{length-1}
alength−1整除。
a
<
=
n
3
a<=\sqrt[3]{n}
a<=3n可以直接暴力枚举,对于每个最后一项,不同的
<
a
<a
<a且
g
c
d
(
a
,
b
)
=
1
gcd(a,b)=1
gcd(a,b)=1的
b
b
b都可以贡献出一种等比数列,有
φ
(
a
)
\varphi(a)
φ(a)种方案,那么答案就是
∑
a
=
2
n
∑
k
=
4
φ
(
a
)
⌊
n
a
k
−
1
⌋
\sum_{a=2}^n\sum_{k=4} \varphi(a)\lfloor \frac n{a^{k-1}} \rfloor
∑a=2n∑k=4φ(a)⌊ak−1n⌋
对于长度=3的等比数列。
数量为
∑
a
=
2
n
φ
(
a
)
⌊
n
a
2
⌋
\sum_{a=2}^n \varphi(a)\lfloor \frac n{a^{2}} \rfloor
∑a=2nφ(a)⌊a2n⌋
对于
⌊
n
a
2
⌋
\lfloor \frac n{a^{2}} \rfloor
⌊a2n⌋可以数论分块,这个时候可以证明 的取值最多只有
n
3
\sqrt[3]n
3n 种:当
a
<
=
n
3
a<=\sqrt[3]n
a<=3n的时候,只有
n
3
\sqrt[3]n
3n种值,当
a
>
n
3
a>\sqrt[3]n
a>3n的时候,这个商小于等于
n
3
\sqrt[3]n
3n,因此最多也就只有
n
3
\sqrt[3]n
3n种答案。
对于 φ ( a ) \varphi(a) φ(a)需要求前缀和,那么杜教筛就好了,注意预处理的范围要尽量大,因为这个复杂度很玄,需要常数技巧的支撑。
A C C o d e : \rm{AC\ Code:} AC Code:
#include<bits/stdc++.h>
#define LL long long
#define maxn 50000005
#define mod 998244353
using namespace std;
int pr[maxn],cnt_pr,phi[maxn],sp[maxn];
bool vis[maxn];
map<LL,int>mp;
int cnt = 0;
int Phi(LL n){
if(n < maxn) return sp[n];
if(mp.count(n)) return mp[n];
int &ret = mp[n] = (n % mod) * (n % mod + 1) / 2 % mod;
for(LL i=2,nxt;i<=n;i=nxt+1){
nxt = n/(n/i);
ret = (ret - (nxt - i + 1ll) % mod * Phi(n/i)) % mod;
}
return ret;
}
int main(){
phi[1] = sp[1] = 1;
for(int i=2;i<maxn;i++){
if(!vis[i]) pr[cnt_pr++] = i , phi[i] = i-1;
for(int j=0;pr[j]*i<maxn;j++){
vis[i * pr[j]] = 1;
if(i % pr[j] == 0){
phi[i * pr[j]] = phi[i] * pr[j];
break;
}
phi[i * pr[j]] = phi[i] * (pr[j] - 1);
}
sp[i] = (sp[i-1] + phi[i]) % mod;
}
int T;
for(scanf("%d",&T);T--;){
LL n;scanf("%lld",&n);
int ans = (n % mod + (n % mod) * (n % mod - 1) / 2) % mod;
for(LL i=2,nxt;i*i<=n;i=nxt+1){
nxt = floor(sqrt(n/(n/(i*i))));
ans = (ans + 1ll * (Phi(nxt) - Phi(i-1)) * (n/(i*i)%mod)) % mod;
}
int lim = floor(pow(n,1.0/3));
for(int i=2;i<=lim;i++)
for(LL x=1ll*i*i*i;;x*=i){
ans = (ans + phi[i] * 1ll * (n / x % mod)) % mod;
if(x > n / i) break;
}
printf("%d\n",(ans+mod)%mod);
}
}