您的位置:首页 > 移动开发

POJ2773-Happy 2006解题报告

2012-09-29 21:23 183 查看
这道题有很多人用欧拉函数做的,我用的是容斥定理,要找第k个和m互素的数,先二分答案,然后用容斥定理计算在1-ans之间有多少个与m互素的元素,这里要用到容斥定理,

假设1到mid中有k个与m互素,而且mid是最小的一个,那么我们就可以说mid是第k个与m互素的数。。
这样就可以用到2分的思想,讲1到inf进行2分,2分出最小的符合有k个与m互素的数的数就行了。。。

对于就1到mid中有多少个与m互素的数需要用到容斥原理:

比如假设m=12;mid=13

12=2*2*3

那么1到mid中与m不互质的数就有2,3,4,6,8,9,10,12,

其实就是2的所有倍数,以及3的所有倍数

这样我们就 算出与1到13中与12不互素的个数为: 13/2+13/3-13/(2*3)=8;

互素的数就位13-8=5;

View Code

#include<iostream>
#include<cstring>
#include<cstdio>
#define N 1000005
#define inf 0x7fffffff
using namespace std;
typedef long long LL;
bool isprime
;
LL prime
;
LL d[30],f;//这里开到30是因为即使按照最小的素数2来划分,也不会超过20个素因子
int cnt;
void init()
{
cnt=0;
LL i,j;
memset(isprime,true,sizeof(isprime));
for(i=2;i<=N-5;i++)
{
if(isprime[i])
{
prime[cnt++]=i;
for(j=i*i;j<=N-5;j+=i)
isprime[j]=false;
}
}
}
void dfs(LL cur,LL now,LL mid,bool neg,LL &res)//容斥定理的搜索
{
if(cur>=f)
return;
LL n=now*d[cur];
dfs(cur+1,now,mid,neg,res);//不乘的情况
if(neg)
res+=(mid/n);
else
res-=(mid/n);
dfs(cur+1,n,mid,!neg,res);//乘的情况
}
LL sum(LL mid)
{
LL res=0;
dfs(0,1,mid,true,res);
return mid-res;
}
int main()
{
LL m,k,i,j,low,high,mid,ans,temp;
init();
while(scanf("%lld%lld",&m,&k)!=EOF)
{
f=0;
for(i=0;i<cnt;i++)
{
if(m%prime[i]==0)
{
d[f++]=prime[i];
while(m%prime[i]==0)
m/=prime[i];
}
if(m==1)
break;
}
low=1,high=inf;
while(low<=high)
{
mid=(high-low)/2+low;
temp=sum(mid);
if(temp==k)
ans=mid;
if(temp>=k)
high=mid-1;
else
low=mid+1;
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: