P5493 质数前缀统计 题解
前言
借此篇题解记录一下 Min_25 筛中的预处理所有
记号与约定
在本文中若无特殊说明,记号均采用以下定义:
-
-
-
-
-
-
题面中的
k 在本文中记作e 。同时k 失去原有定义。
正文
考虑直接求得
自然有边界
现在考虑从
虽然
所以,第一维只可能是
代码
#include<bits/stdc++.h>
// #define ONLINE_JUDGE
#define INPUT_DATA_TYPE long long
#define OUTPUT_DATA_TYPE int
INPUT_DATA_TYPE read(){register INPUT_DATA_TYPE x=0;register char f=0,c=getchar();while(c<'0'||'9'<c)f=(c=='-'),c=getchar();while('0'<=c&&c<='9')x=(x<<3)+(x<<1)+(c&15),c=getchar();return f?-x:x;}void print(OUTPUT_DATA_TYPE x){if(x<0)x=-x,putchar('-');if(x>9)print(x/10);putchar(x%10^48);return;}
long long mod;
int K;
long long qpow(register long long base,register long long e){
register long long res=1;
base%=mod;
while(e){
if(e&1) res=(res*base)%(mod);
base=(base*base)%(mod);
e>>=1;
}
return res;
}
#define INV_DATA_TYPE long long
INV_DATA_TYPE exgcd(INV_DATA_TYPE a,INV_DATA_TYPE b,INV_DATA_TYPE &x,INV_DATA_TYPE &y){
if(!b){
x=1;
y=0;
return a;
}
INV_DATA_TYPE d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
INV_DATA_TYPE inv(INV_DATA_TYPE n,INV_DATA_TYPE p){
n%=p;
INV_DATA_TYPE x,y;
exgcd(n,p,x,y);
x%=p;
return x>=0?x:x+p;
}
long long pl[20],pr[20],fac[20],y[20],b[20];
long long S_all(long long n){
register int i;
register long long ans=0,a;
pl[0]=pr[K+3]=1;
for(i=1;i<=K+2;i++) pl[i]=pl[i-1]*(n%mod-i)%mod;
for(i=K+2;i>=1;i--) pr[i]=pr[i+1]*(n%mod-i)%mod;
for(i=1;i<=K+2;i++){
a=pl[i-1]*pr[i+1]%mod;
(ans+=y[i]*a%mod*b[i]%mod)%=mod;
}
return (ans+mod)%mod;
}
long long sp[1000010],n;
long long g[1000010],val[1000010];
int sqrtN,cntId,idx_s[1000010],idx_b[1000010];
std::bitset<1000010> isPrime;
long long prime[1000010];
int cntPri;
void Euler(int n){
register long long i,j;
for(i=2;i<=n;++i){
if(!isPrime[i]){
prime[++cntPri]=i;
sp[cntPri]=(sp[cntPri-1]+qpow(i,K))%mod;
}
for(j=1;j<=cntPri&&prime[j]*i<=n;++j){
isPrime[prime[j]*i]=1;
if(!(i%prime[j])) break;
}
}
}
int getIdx(long long a){
if(a<=sqrtN) return idx_s[a];
else return idx_b[n/a];
}
void initG(){
register long long i,nxt,tmp;
register int id;
for(i=1;i<=n;i=nxt+1){
nxt=n/(n/i);
val[++cntId]=n/i;
g[cntId]=(S_all(val[cntId])+mod-1)%mod;
if(n/i<=sqrtN) idx_s[n/i]=cntId;
else idx_b[n/(n/i)]=cntId;
}
for(register int i=1,j;i<=cntPri;++i){
tmp=qpow(prime[i],K);
for(j=1;j<=cntId&&prime[i]*prime[i]<=val[j];++j){
id=getIdx(val[j]/prime[i]);
(g[j]+=mod-tmp*(g[id]+mod-sp[i-1])%mod)%=mod;
}
}
return;
}
long long inv6;
long long s2(long long n){
n%=mod;
return n*(n+1)%mod*(n*2+1)%mod*inv6%mod;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("name.in", "r", stdin);
freopen("name.out", "w", stdout);
#endif
register long long res=0,i,nxt;
sqrtN=std::sqrt(n=read());
K=read();
mod=read();
for(i=fac[0]=1;i<=K+2;i++) fac[i]=fac[i-1]*i%mod,y[i]=(y[i-1]+qpow(i,K))%mod;
for(i=1;i<=K+2;i++) b[i]=inv(fac[i-1]*((K-i)&1?mod-1:1)%mod*fac[K+2-i],mod)%mod;
inv6=inv(6,mod);
Euler(sqrtN);
initG();
for(i=1;i<=sqrtN;i=nxt+1){
nxt=std::min(n/(n/i),(long long)sqrtN);
(res+=(s2(nxt)+mod-s2(i-1))*g[getIdx(n/i)])%=mod;
}
print(res);
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}