bzoj2440(二分+莫比乌斯函数)

来源:互联网 发布:美萍美容美发软件 编辑:程序博客网 时间:2024/05/22 02:00

      • 题目大意
      • 思路
      • Code

题目大意:

询问从一开始的第k个不是完全平方数的正整数倍的数

思路:

这当考试题目做的,一开始以为用筛法预处理所有数,然后O(1)回答询问,结果n有1e9,显然O(n)都不可做.然后考虑枚举完全平方数的平方因子,这样把数据缩小到1e4~1e5左右.
然后我们发现直接询问第k个有些难做,不如把问题转化为一个存在性问题:即是否存在一个数n使得前面有k个数.这样我们二分这个n.
现在需要询问有多少在n之前的数对这个产生了贡献.
即:有多少个在n之前的数,分解后为的最高次数为1.
那么用容斥原理解决(就是莫比乌斯函数)即可

Code:

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=1e5+10;typedef long long ll;int prime[N],mu[N],n,T,K;bool check[N];void getmu(){    memset(check,0,sizeof(check));    mu[1]=1;    int tot=0;    for(int i=2;i<=N;i++) {        if(!check[i]) {            prime[++tot]=i;            mu[i]=-1;        }        for(int j=1;j<=tot;j++) {            if(i*prime[j]>N) break;            check[i*prime[j]]=1;            if(i%prime[j]==0) {                mu[i*prime[j]]=0;                break;            }else {                mu[i*prime[j]]=-mu[i];            }        }    }}bool jud(int t){    ll cnt=0;    for(int i=1;i*i<=t;i++)         cnt+=t/(i*i)*mu[i];    if(cnt>=K) return 1;    else return 0;}void solve(){    ll l=1,r=K<<1,mid,ans=0;     while(l<=r) {        mid=(l+r)>>1;        if(jud(mid)==1) ans=mid,r=mid-1;        else l=mid+1;    }       printf("%lld\n",ans);}ll cal(int x){    ll sum=0;    int t=sqrt(x);    for(int i=1;i<=t;i++)        sum+=x/(i*i)*mu[i];    return sum;}int main(){    freopen("number.in","r",stdin);    freopen("number.out","w",stdout);    getmu(); scanf("%d",&T);    while(T--){        scanf("%d",&K);        solve();    }    return 0;}
阅读全文
0 0
原创粉丝点击