51nod1847 奇怪的数学题
Description
http://www.51nod.com/Challenge/Problem.html#problemId=1847
计算下式
函数表示第二大的 ,当 时 ,例如
Solution
写这题是为了复习模板
设 表示 的最大真因子,原式改写成
后半部分是杜教筛模板,外层套整除分块即可得到,那么仍需求出 函数前缀和
函数本身并没有什么特别的积性,但是考察 筛法的第一个 的过程:依次枚举质因子并从每个 中去掉 在这其中的贡献
形式化的表达式写作
其中 g[n/pri[i]][i-1]-g[pri[i-1]][i-1]
的含义恰是将那些最大质因子为 pri[i]
的数字去掉最大质因子之后剩下的数字的 次幂值之和,那么可以贡献给
另外由于要处理 的值,所以在 筛法的过程中需要计算范围内的质数数量,这相对 trivial
在 筛的初始状态需要赋值 ,因为模数的原因不能使用依赖于逆元的 插值
一种可能的解决方法是出于指数很小使用第二类斯特林数,即
由于连续 个数中必然有一个 的倍数,所以找到之除掉后就没有除法操作了
Code
#define uint unsigned int
const int N=2e6+10;
int pri[N],cnt,fl[N];
map<int,uint> mp;
uint phi[N],Str[100][100],res[N],num[N],f[N],sum[N];
int R[N],tot,n,k,bl,id1[N],id2[N];
inline uint getphi(int n){
if(n<=2e6) return phi[n];
if(mp.count(n)) return mp[n];
uint ans=(n&1)?(uint)(n+1)/2*n:(uint)n/2*(n+1);
for(int l=2,r;l<=n;l=r+1){
r=n/(n/l);
ans-=(uint)(r-l+1)*getphi(n/l);
}
return mp[n]=ans;
}
inline int getid(int x){
if(x<=bl) return id1[x];
else return id2[n/x];
}
inline uint calc(int n){
int pos=getid(n);
return res[pos]+num[pos];
}
inline uint S(int n,int k){
uint ans=0;
rep(j,0,k){
uint tmp=1,now=n+1;
bool fl=0;
rep(i,0,j){
if(fl==0&&now%(j+1)==0) tmp*=now/(j+1),fl=1;
else tmp*=now;
--now;
}
ans+=tmp*Str[k][j];
}
return ans;
}
inline uint ksm(uint x,int y){
uint res=1;
for(;y;y>>=1,x=x*x) if(y&1) res*=x;
return res;
}
signed main(){
n=2e6; phi[1]=1;
for(int i=2;i<=n;++i){
if(!fl[i]) phi[i]=i-1,pri[++cnt]=i;
for(int j=1;j<=cnt&&1ll*i*pri[j]<=n;++j){
fl[i*pri[j]]=1;
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}else{
phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
}
for(int i=1;i<=n;++i) phi[i]+=phi[i-1];
n=read(); k=read(); bl=sqrt(n);
Str[1][1]=1;
rep(i,2,50){
rep(j,1,i){
Str[i][j]=Str[i-1][j]*j+Str[i-1][j-1];
}
}
for(int l=1,r;l<=n;l=r+1){
R[++tot]=n/l; r=n/R[tot];
f[tot]=S(R[tot],k)-1;
num[tot]=R[tot]-1;
// Do not consider ones so subtract them
if(R[tot]<=bl) id1[R[tot]]=tot; else id2[n/R[tot]]=tot;
}
for(int j=1;j<=cnt;++j){
uint now=ksm(pri[j],k);
sum[j]=sum[j-1]+now;
for(int i=1;i<=tot&&1ll*pri[j]*pri[j]<=R[i];++i){
int pos=getid(R[i]/pri[j]);
f[i]-=(f[pos]-sum[j-1])*now;
res[i]+=f[pos]-sum[j-1];
num[i]-=num[pos]-(j-1); // Numbers except from primes
}
}
uint ans=0;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(2*getphi(n/l)-1)*(calc(r)-calc(l-1));
}
print(ans);
return 0;
}
代码不附带缺省源,如果需要可以去 【遇到困难睡大觉】 一文中粘贴并去掉 #define int long long
感觉最近代码越来越蓬松了,都快不可读了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律