SPOJ 4168 Square-free integers

求1-n之间Square-free integers的个数。

第一种方法是裸的容斥原理,枚举每一个质因子要还是不要,然后用总数减去存在平方质因子的数的个数。

剪枝的方法是在dfs内进行循环,这样避免每次都去递归试探一个质因子不要的情况。

代码基本是抄的,剪枝很强力。

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int X=10000100;
bool su[X];
long long s[X/10],top;
void make(){
    ll i,j;
    for(i=2;i<X;i++)if(!su[i]){
        for(j=i*i;j<X;j+=i)su[j]=1;
        s[top++]=i*i;
    }
}
ll as,n;
ll dfs(int id,ll d){
    ll sum=0;
    while(id<top&&s[id]<=n/d ){
        sum += n/(d*s[id])-dfs(id+1,d*s[id]);
        id++;
    }
    return sum;
}

int main(){
    make();
    int i,j,cs;
    for(scanf("%d",&cs);cs--;){
        as=0;
        scanf("%lld",&n);
        printf("%lld\n",n-dfs(0,1));
    }
    return 0;
}

第二种方法是正解,感谢Ceno大神仔细的教导。。

把每一个数写成p^2*q的形式,其中p是最大的能构成平方的因子,这样表示使得每一个数都是唯一的。

假设p=2,那么考虑1-n内有多少个可以写成2^2*q的数,是n/2/2个,

这其中也包括p!=2的情况,但是可以通过容斥把这些情况减去。

而加减的系数是通过mobius函数决定的,

于是通过枚举p,最后的答案是sum(n/p/p*mobius[p]);

枚举p的复杂度是O(n),求mobius的复杂度也有O(n)的算法。

代码如下。

#include<cstdio>
const int X=10000010;
bool su[X];
int u[X],s[X],top;
void make(){
    long long i,j;
    u[1]=1;
    for(i=2;i<X;i++){
        if(!su[i]){
            s[top++]=i;
            u[i]=-1;
        }
        for(j=0;j<top&&i*s[j]<X;j++){
            su[i*s[j]]=1;
            if(i%s[j])u[i*s[j]]=u[i]*u[s[j]];
            else break;
        }
    }
}
int main(){
    make();
    int i,cs;
    long long n,sum;
    for(scanf("%d",&cs);cs--;){
        sum=0;
        scanf("%lld",&n);
        for(i=1;i<=n/i;i++)
            if(u[i])
                sum+=n/i/i*u[i];
        printf("%lld\n",sum);
    }
    return 0;
}





你可能感兴趣的:(容斥原理,mobius函数)