题目
思路来源
https://blog.csdn.net/jk_chen_acmer/article/details/101558425
题解
min25筛的部分用的比较基础,用了一个区间素数个数,一个区间素数和
首先,考虑这个式子,阶乘的话,1被计了n次,2被计了n-1次,i被计了n+1-i次
则答案等价于求,即
f函数,实际上等价于统计每个p出现了多少次,最后求个总和,
考虑勒让德定理,统计每个出现了多少次,
计,对于
的每个倍数
,其对答案的贡献都是
,
所以提一个出来等差数列求和,即知这部分最终答案为
暴力的做的话,从1往上枚举幂次e至超出限制,累加答案即可,但复杂度不大行,
所以,对于e>=2的,由于此时
,暴力枚举p统计上述的f和g,
而对于e=1的情形,需要数论分块解决[l,r]区间内的素数和、素数个数,
此时,套一下min25筛的质数处理部分,前缀和作差即可
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+10,mod=998244353,inv2=(mod+1)/2;
ll n,Sqr,w[N],ans,ret;
ll pri[N],id1[N],id2[N],h[N],g[N],c;
bool zs[N];
int tot,sp[N];
void pre(int n){
zs[1]=true;
for(int i=2;i<=n;++i){
if(!zs[i]){
pri[++tot]=i;
sp[tot]=(sp[tot-1]+i)%mod;
}
for(int j=1;j<=tot&&i*pri[j]<=n;++j){
zs[i*pri[j]]=true;
if(i%pri[j]==0)break;
}
}
}
int main(){
scanf("%lld",&n);
Sqr=sqrt(n);
pre(Sqr);
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);w[++c]=n/l;
h[c]=(w[c]-1)%mod;
g[c]=(w[c]%mod)*((w[c]+1)%mod)%mod*inv2%mod-1;
if(w[c]<=Sqr)id1[w[c]]=c;
else id2[r]=c;
}
for(int j=1;j<=tot;++j){
for(int i=1;i<=c && pri[j]*pri[j]<=w[i];++i){
int k=(w[i]/pri[j]<=Sqr)?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])];
(g[i]-=1ll*pri[j]*(g[k]-sp[j-1])%mod)%=mod;
(h[i]-=h[k]-j+1)%=mod;
}
}
/*
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);
ll x=(n/l)%mod;
ans=(ans+x)%mod;
}
ans=(ans-n%mod+mod)%mod;
*/
for(int j=1;j<=tot && pri[j]*pri[j]<=n;++j){//枚举p<=sqrt(n)
for(ll t2=pri[j]*pri[j];t2<=n;t2*=pri[j]){//枚举p的幂次e>=2
ll v=(n/t2)%mod,v2=v+1;
ans=(ans+(v*v2/2)%mod*t2%mod)%mod;
ret=(ret+v)%mod;
}
}
int pre=0,now=0;//[l,r]区间段求素数个数 求素数区间和 nowr-prer
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);
if(r<=Sqr)now=id1[r];
else now=id2[n/r];
ll v=(n/l)%mod,v2=v+1;
ll sump=(g[now]-g[pre])%mod,nump=(h[now]-h[pre])%mod;
//printf("l:%lld r:%lld sump:%lld nump:%lld now:%d pre:%d wnow:%lld wpre:%lld\n",l,r,sump,nump,now,pre,w[now],w[pre]);
ans=(ans+(v*v2/2%mod)*sump%mod+mod)%mod;
ret=(ret+(v%mod)*nump%mod+mod)%mod;
pre=now;
}
printf("%lld\n",((n+1)%mod*ret-ans+mod)%mod);
return 0;
}