bzoj 2440 莫比乌斯反演应用

来源:互联网 发布:怀化瀚云网络 郭小平 编辑:程序博客网 时间:2024/06/08 08:58



链接:戳这里


2440: [中山市选2011]完全平方数


Time Limit: 10 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]
Description

小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些
数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而
这丝毫不影响他对其他数的热爱。 
这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一
个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了
小X。小X很开心地收下了。 
然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?

Input

包含多组测试数据。文件第一行有一个整数 T,表示测试
数据的组数。 
第2 至第T+1 行每行有一个整数Ki,描述一组数据,含义如题目中所描述。 

Output

含T 行,分别对每组数据作出回答。第 i 行输出相应的
第Ki 个不是完全平方数的正整数倍的数。

Sample Input





13 

100 

1234567 
Sample Output



19 

163 

2030745 
HINT

对于 100%的数据有 1 ≤ Ki ≤ 10^9,  T ≤ 50


思路:首先我们要把完全平方数和完全平方数的倍数叉掉,  4 9 25  12 16 18 25 50  这些类似的

莫比乌斯反演的筛选函数里面有一个mu[i]函数,是一个积性函数  mu[3]=-1 mu[6]=1

可以自行百度,然后这里可以很巧妙的应用这个mu[i]函数, 显然我们筛4 9 的倍数的时候36会筛掉两次,但是mu[6]=1,我们又可以用这个加回来  具体看代码吧


代码:

 

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<vector>#include <ctime>#include<queue>#include<set>#include<map>#include<stack>#include<iomanip>#include<cmath>#define mst(ss,b) memset((ss),(b),sizeof(ss))#define maxn 0x3f3f3f3f#define MAX 1000100///#pragma comment(linker, "/STACK:102400000,102400000")typedef long long ll;typedef unsigned long long ull;#define INF (1ll<<60)-1using namespace std;int n,cnt;int mu[1000100],prime[1000100],vis[1000100];void Moblus(){    mu[1]=1;    cnt=0;    mst(vis,0);    for(int i=2;i<=1000000;i++){        if(!vis[i]){            prime[++cnt]=i;            mu[i]=-1;        }        for(int j=1;j<=cnt;j++){            if(i*prime[j]>1000000) break;            vis[i*prime[j]]=1;            if(i%prime[j]==0){                mu[i*prime[j]]=0;                break;            } else mu[i*prime[j]]=-mu[i];        }    }}ll solve(ll n){    ll ans=0;    for(ll i=1;i*i<=n;i++){        ans+=(n/(i*i))*mu[i];    }    return ans;}int main(){    Moblus();   /// for(int i=1;i<=60;i++) cout<<i<<"="<<mu[i]<<endl;    int T,k;    scanf("%d",&T);    while(T--){        scanf("%d",&k);        ll l=k,r=1e10,mid,ans;        while(l<r){            mid=(l+r)/2;            if(solve(mid)<k) l=mid+1;            else r=mid,ans=mid;        }        cout<<ans<<endl;    }    return 0;}

0 0
原创粉丝点击