#杜教筛,欧拉函数,整除分块#HDU 6683 Rikka with Geometric Sequen
题目
由\(1,2,\dots,n-1,n\)组成的序列中有多少个子序列是等比数列\((n\leq 5*10^{17})\)
分析
分类讨论,先设公比为\(q=\frac{i}{j}[gcd(i,j)==1,i>j]\)
首先长度为1或2的有\(\frac{n(n+1)}{2}\)个
考虑长度大于3的可以暴力处理,枚举长度和分子\(i\)
公比不同的等比数列有\(\varphi(i)\)个,首项一共有\(\lfloor\frac{n}{i^{len-1}}\rfloor\)中情况
那么
\[ans=\sum_{i=2}^n\sum_{len=4}\varphi(i)\lfloor\frac{n}{i^{len-1}}\rfloor
\]
长度等于3同理可得
\[ans=\sum_{i=2}^n\varphi(i)\lfloor\frac{n}{i^2}\rfloor
\]
整除分块+杜教筛,就不会TLE了
怎么用杜教筛??套模板就可以了
代码
#include <cstdio>
#include <cctype>
#include <cmath>
#include <map>
#define rr register
using namespace std;
const int N=40000011,mod=998244353;
int phi[N],prime[N],Cnt; bool v[N];
typedef long long lll; map<int,int>uk;
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline signed od(int x,int y){return x<y?x+mod-y:x-y;}
inline void Pro(int n){
phi[1]=1;
for (rr int i=2;i<=n;++i){
if (!v[i]) prime[++Cnt]=i,phi[i]=i-1;
for (rr int j=1;j<=Cnt&&prime[j]<=n/i;++j){
v[i*prime[j]]=1,phi[i*prime[j]]=phi[i]*(prime[j]-1);
if (i%prime[j]==0) {
phi[i*prime[j]]+=phi[i];
break;
}
}
}
for (rr int i=2;i<=n;++i) phi[i]=mo(phi[i-1],phi[i]);
}
inline signed sphi(int n){
if (n<=N-11) return phi[n];
if (uk.find(n)!=uk.end()) return uk[n];
rr int ans=(1ll*n*(n+1)>>1)%mod;
for (rr int l=2,r;l<=n;l=r+1)
r=n/(n/l),ans=od(ans,1ll*sphi(n/l)*(r-l+1)%mod);
return ans;
}
signed main(){
Pro(N-11); rr int Test;
for (scanf("%d",&Test);Test;--Test){
rr lll n,t; scanf("%lld",&n);
rr int ans=((n%mod)*((n%mod)+1)>>1)%mod;
rr int t1=sqrt(n),t2=pow(n,1.0/3);
for (rr int l=2,r,w;l<=t1;l=r+1)
t=n/l/l,r=sqrt(n/t),ans=mo(ans,t*od(sphi(r),sphi(l-1))%mod);
for (rr int i=2;i<=t2;++i)
for (rr lll t=1ll*i*i*i;;t*=i){
ans=mo(ans,(n/t)*od(phi[i],phi[i-1])%mod);
if (t>n/i) break;
}
printf("%d\n",ans);
}
return 0;
}