51nod [1220 约数之和]
题意
题意:已知 ,求 ,其中 。
题解
首先我们先来看一个结论: 。其中 表示在 成立的时候这个值为 ,不成立时这个值为 。
为啥这个结论是对的呢?前面的 实际上是在枚举这个约数的值,但是为什么在 后面还要乘上一个数字呢?
因为如果不乘那个数字会重复计算,例如在 时 和 这两组取值都可以得到一个 的约数 ,这时候这个约数就被计算了两遍。加上这个约束就不会重复计算了。
下来我们来推式子。
欢乐的颓柿子时间
令
那么上面的式子可以变成 。
可以发现,如果可以比较快速求出 的值以及 的前缀和就可以对整个式子进行数论分块。
Part1
我们先来看一下 的值如何求。
这个玩意也可以数论分块(瞬间窒息
Part2
我们设 。
那么我们要求的 。
既然要在 范围内求一个函数(就是 )的前缀和,并且这还是一个积性函数,我们首先考虑杜教筛。
不难发现 ,那我们设 。
让我们把杜教筛的式子写出来:
的前缀和挺好求,不说了。
我们来推一下 的。
Game over!
代码
#include<cstdio>
#include<map>
using namespace std;
const int mod=1000000007;
using ll=long long;
inline int read()
{
int s=0,w=1;char ch;
while((ch=getchar())>'9'||ch<'0') if(ch=='-') w=-1;
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int pri[1000001];
bool is[1000001];
ll f[1000001];
map<int,ll>mf;
ll ans;
int n;
ll run(int l,int r)
{
return (ll)(r-l+1)*(l+r)/2%mod;
}
ll get(int num)
{
if(num<=1000000) return f[num];
if(mf.count(num)) return mf[num];
// printf("get %d\n",num);
ll val=1;
for(int l=2,r;l<=num;l=r+1)
{
r=num/(num/l);
val=(val-run(l,r)*get(num/l))%mod;
}
return mf[num]=(val+mod)%mod;
}
ll getpre(int num)
{
ll ans=0;
for(int l=1,r;l<=num;l=r+1)
{
r=num/(num/l);
ans=(ans+run(l,r)*(num/l))%mod;
}
return ans*ans%mod;
}
int main()
{
n=1000000,f[1]=1;
for(int i=2;i<=n;i++)
{
if(!is[i]) pri[++pri[0]]=i,f[i]=-1;
for(int j=1;j<=pri[0]&&i*pri[j]<=n;j++)
{
is[i*pri[j]]=1;
if(i%pri[j]==0) break;
f[i*pri[j]]=-f[i];
}
}
for(int i=1;i<=n;i++) f[i]=(f[i]*i+f[i-1]+mod)%mod;
n=read();
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
ans=(ans+(get(r)-get(l-1))*getpre(n/l))%mod;
}
printf("%lld\n",(ans+mod)%mod);
return 0;
}
本文来自博客园,作者:Wuyanru,转载请取得作者同意并注明原文链接:https://www.cnblogs.com/Wuyanru/p/51nod-1220.html
本文内容如有侵权行为,请联系作者删除,qq:1395170470
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!