[51nod1244]莫比乌斯函数之和
题意:求区间[a,b]的莫比乌斯函数µ之和。 a,b<=1011
题解:很容易把区间求和改为求前缀和并求差,即要求M(x)=∑n1μ(x)考虑化简
莫比乌斯函数存在一个性质,也就是∑d|nμ(d)=[n=1],那么∑ni=1∑d|iμ(d)=1
这个式子比较复杂,我们转而考虑对于每一个d,它被计算了多少次,也就是∑ni=1∑⌊n/i⌋d=1μ(d) ,这个式子=∑ni=1M(⌊n/i⌋)=1 所以说,M(n)=1−∑ni=2M(⌊n/i⌋)
⌊n/i⌋/i只有√(n)种,复杂度在预处理出前k=n23的M值时最小,然后记忆化搜索可以在O(n23)内解决。
我们发现在计算中⌊n/i⌋有很多会被重复计算,所以可以手写一个map来极大地提升效率。
第一次用latex写公式,还好有个很牛逼的网站
估计是模数选的好,随便写写RANK1啦。
#include<iostream> #include<cstdio> #include<cmath> #define MAXN 5000000 #define mod 2333333 #define ll long long using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } struct my_map{ ll x;int ans,next; }e[MAXN+5]; int f[MAXN+5],ans=0,num=0,s[MAXN],head[mod+5]; bool b[MAXN+5]; void ins(ll x,int sum) { int j=x%mod; e[++num]=(my_map){x,sum,head[j]}; head[j]=num; } int calc(ll n) { if(n<=MAXN) return f[n]; for(int i=head[n%mod];i;i=e[i].next) if(e[i].x==n)return e[i].ans; int sum=1,q=sqrt(n); for(int i=2;i<=q;i++) sum-=calc(n/i); q=n/(q+1); for(int i=1;i<=q;i++) sum-=(n/i-(n/(i+1)))*calc(i); ins(n,sum); return sum; } int main() { f[1]=1;b[1]=1; for(int i=2;i<=MAXN;i++) { if(!b[i]) s[++num]=i,f[i]=-1; for(int j=1;j<=num&&s[j]*i<=MAXN;j++) { int t=s[j]*i; b[t]=1; if(i%s[j]==0){f[t]=0;break;} f[t]=-f[i]; } } for(int i=2;i<=MAXN;i++) f[i]+=f[i-1]; num=0; ll x=read();ans-=calc(x-1); x=read();ans+=calc(x); cout<<ans; return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步