51Nod 欢乐手速场1 C 开心的小Q[莫比乌斯函数]
如果一个数字存在一个约数是完全平方数,那么小Q就认为这个数是有趣的。
小Q喜欢收集有趣的数字,每找到一个有趣的数,小Q就会变得很开心。
小Q发现12是有趣的,18也是有趣的,它们都是36的约数,而在36的约数中,还有3个数是有趣的,它们是4、9、36。
小Q很好奇,在a~b里每个数字各有多少个有趣的约数,由于a和b太大了,所以他只想知道这些个数之和是多少。
例如4有1个有趣的约数,8有2个有趣的约数,9有1个有趣的约数,所以1~10里每个数的有趣约数个数之和是4。
Input
输入数据包括2个数:a, b,中间用空格分隔。(1≤a≤b≤10^9)
Output
输出a~b里每个数字的有趣约数个数之和。
Input示例
1 10
Output示例
4
标解:http://www.51nod.com/contest/problemSolution.html#!problemId=1742
里面的式子改写一开始一直不明白,稍微有点明白了,说说另一种想的方法吧
最暴力的是枚举数字再枚举约数看看是不是平方因子数了
一个简单的优化是枚举约数i,约数i的贡献(倍数的数量)就是[n/i]
但还是会T
一个巧妙的想法是我们枚举是几倍,当前枚举的是i倍,那么满足i倍<=n的数字就是<=[n/i],答案加上<=[n/i]的平方因子数的个数,就是标解中最后的式子了
计算的时候用了两次分块n/(i*i)和n/i做到O(n^2/3)
然而比只一次分块还慢是什么鬼?sqrt的问题吗
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; typedef long long ll; const int N=1e5+5; inline int read(){ char c=getchar();ll x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int a,b; bool notp[N]; int p[N],mu[N]; void sieve(int n){ mu[1]=1; for(int i=2;i<=n;i++){ if(!notp[i]) p[++p[0]]=i,mu[i]=-1; for(int j=1;j<=p[0]&&i*p[j]<=n;j++){ notp[i*p[j]]=1; if(i%p[j]==0) break; mu[i*p[j]]=-mu[i]; } } //for(int i=1;i<=n;i++) printf("mu %d %d\n",i,mu[i]); //for(int i=1;i<=n;i++) mu[i]+=mu[i-1]; } //int F(int n){ // int _=0,r=0,m=sqrt(n); // for(int i=1;i<=m;i=r+1){ // r=n/(n/(i*i)); // _+=n/(i*i)*(mu[r]-mu[i-1]); // } // return n-_; //} int f(int n){ int _=0,m=sqrt(n); for(int i=1;i<=m;i++) _+=n/(i*i)*mu[i]; return n-_; } ll S(int n){//printf("n %d\n",n); ll ans=0;int r=0; for(int i=1;i<=n;i=r+1){ r=n/(n/i); ans+=(r-i+1)*f(n/i); //printf("f %d %d %d %d\n",n/i,i,r,f(n/i)); } return ans; } int main(){ //freopen("in","r",stdin); a=read();b=read(); sieve(sqrt(b)+1); printf("%lld",S(b)-S(a-1)); }
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; typedef long long ll; const int N=1e5+5; inline int read(){ char c=getchar();ll x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int a,b; bool notp[N]; int p[N],mu[N]; void sieve(int n){ mu[1]=1; for(int i=2;i<=n;i++){ if(!notp[i]) p[++p[0]]=i,mu[i]=-1; for(int j=1;j<=p[0]&&i*p[j]<=n;j++){ notp[i*p[j]]=1; if(i%p[j]==0) break; mu[i*p[j]]=-mu[i]; } } //for(int i=1;i<=n;i++) printf("mu %d %d\n",i,mu[i]); for(int i=1;i<=n;i++) mu[i]+=mu[i-1]; } int F(int n){//printf("F %d\n",n); int _=0,r=0,m=sqrt(n); for(int i=1;i<=m;i=r+1){ r=sqrt(n/(n/(i*i)));//printf("r %d\n",r); _+=n/(i*i)*(mu[r]-mu[i-1]); } return n-_; } ll S(int n){//printf("n %d\n",n); ll ans=0;int r=0; for(int i=1;i<=n;i=r+1){ r=n/(n/i); ans+=(r-i+1)*F(n/i); //printf("F %d %d %d %d\n",n/i,i,r,F(n/i)); } return ans; } int main(){ //freopen("in","r",stdin); a=read();b=read(); sieve(sqrt(b)+1); printf("%lld",S(b)-S(a-1)); }
Copyright:http://www.cnblogs.com/candy99/