BZOJ 2440 : [中山市选2011] 完全平方数 (二分+容斥原理+莫比乌斯函数)

版权声明:布呗之路的守望者 https://blog.csdn.net/hypHuangYanPing/article/details/82391814
/**
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2440
题意:第k个不含平方因子的数  二分查询第k个; 二分的上届怎么证明呀...  .......
转换为1-->x含平方因子的数的个数;
直接暴力枚举即可  1-->sqrt(x);
对于上述的式子 首先得想到容斥原理
举个栗子吧.... 假如说  ans = n/(1*1)-n/(2*2)-n/(3*3)......
这样话 不难发现 1--->n  n/(6*6) 6为2*3 分解后存在两个质数,因此在容斥内是加;
对于上述的容斥  不难发现 容斥系数其实就是莫比乌斯函数 可以类比定义想想为什么....
计算只需要到sqrt(k)  时间复杂度 t*sqrt(max(ki))*log(2*ki)
*/

/**
ccpc 1 sell buy 
example1:  4天 
        1 2 10 9
 
ans  =  -1 + -2 + 10 +9 = 16
乘数    -1   -1 + 1  +1
换句话来说 就是   你对与每一个数字  乘上 1 -1 0 使得最后的和最大
保证:每天乘数的前缀和小于等于0 ;
前缀和 :  -1   或者  -1 + -1  或者 -1 + -1 + 1 或者 -1 + -1 + 1 +1;
那么上面的数 对应相乘 累加后和就是最大了....可自行手动模拟一下..

5
9 5 9 10 5
ans = -5+10 可自行模拟;

2
2 1 
ans = 0; 

*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn=1e5+7;
int  mu[maxn],prime[maxn];
bool vis[maxn];

int cnt=0;
ll k;

void get_mu(){
    memset(vis,0,sizeof(vis));
    mu[1]=1;
    for(int i=2;i<maxn;i++){
        if(!vis[i]) prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt;j++){
            if(i*prime[j]>=maxn) break;
            vis[i*prime[j]]=1;
            if(i%prime[j]==0) mu[i*prime[j]]=0;
            else mu[i*prime[j]]=-mu[i];
            if(i%prime[j]==0) break;
        }
    }
}

ll judge(ll x){
    ll ans=0;
    ll tmp=(ll)ceil(sqrt((double)x));
    tmp=min(tmp,x);
    for(ll i=1;i<=tmp;i++) ans+=1ll*mu[i]*(x/(i*i));
    return ans>=k;
}

ll binary_Search(){
    ll l=0,r=2*k;
    while(r-l>1){
        ll mid=(l+r)/2;
        if(judge(mid)) r=mid;
        else l=mid;
    }
    return r;
}
int main (){
    get_mu();
    int t;scanf("%d",&t);
    while(t--){
        scanf("%lld",&k);
        ll ans=binary_Search();
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hypHuangYanPing/article/details/82391814