#杜教筛,欧拉函数,整除分块#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;
}
posted @ 2020-03-29 23:03  lemondinosaur  阅读(168)  评论(0编辑  收藏  举报