二分+mu函数实质及应用(原理)!——bzoj2440好题

首先想到用二分来判断

不是平方数的倍数,即没有次数>=2的质因子
显然用容斥原理,即所有答案-1个质因子的平方的所有倍数+2个质因子的所有平方倍...
等价于对于每个数,如果它有奇数个质因子,那么其贡献系数是-1,反之则是1,

如果自己本身有平方因子(比如2*2*3),那么其贡献系数是0,因为已经被前面的筛掉了(1的时候+1,2,3的时候-1,2*3的时候+1,最后已经成为0了),根本不用去管它

那么可以发现i的系数恰好是mu[i]

其实由这题可以发现mu[i]函数的意义,即容斥系数

本题用容斥筛出i的倍数时 对应的系数恰好是 mu[i]是因为:mu[i]的本质就是来筛i的倍数的

设f(n)是原函数,g(n)是和函数

mu[p1]=-1 是因为 f(n)必须要减去一个g(n/p1)

mu[p1*p2]=1是因为 f(n)=g(n)-g(n/p1)-g(n/p2),多减掉了一个g(n/p1/p2)

mu[p1^k*p2]=0 是因为 f(n)=g(n)-g(n/p1)-g(n/p2)+g(n/p1/p2) 里 的g(n/p1^k/p2)已经被做成0了

  g(n/p1的所有倍数)系数-1,g(n/p2的所有倍数)系数-1,g(n/p1/p2)的所有倍数系数+1,所以g(n/p1/p2的所有倍数)的系数最后变成了0,包括g(n/p1/p1/p2)之类的系数

所以不需要再加减了

#define N 100000
using namespace std;
typedef long long LL;
const LL inf = (1LL<<31)-1;
const int MAXN = 100011;
LL l,r;
int ans;
int mobius[MAXN],k;
int prime[MAXN],cnt;
bool ok[MAXN];

inline int getint()
{
    int w=0,q=0; char c=getchar();
    while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 
    while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;
}

inline void init(){
    mobius[1]=1;
    for(int i=2;i<=N;i++) {
    if(!ok[i]) prime[++cnt]=i,mobius[i]=-1;
    for(int j=1;j<=cnt && prime[j]*i<=N;j++) {
        ok[i*prime[j]]=1;
        if(i%prime[j]) mobius[i*prime[j]]=-mobius[i];
        else { mobius[i*prime[j]]=0; break; }
    }
    }
}

inline bool check(LL x){
    LL div=sqrt(x); int tot=0;
    for(int i=1;i<=div;i++) {
    tot+=mobius[i] * (x/(i*i));
    }
    //tot=x-tot;
    if(tot>=k) return true;
    return false;
}

inline void work(){
    init(); int T=getint(); LL mid;
    while(T--) {
    k=getint(); l=1; r=inf; ans=inf;
    while(l<=r) {
        mid=(l+r)/2;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
    }
}

int main()
{
    work();
    return 0;
}

 

posted on 2019-07-07 16:07  zsben  阅读(297)  评论(0编辑  收藏  举报

导航