题目描述:
题意给三个数m,n,k求第k个与m,n同时互质的数,lcm(m,n)的数据太大不好直接求然后循环找,那么就容斥了,这里涉及到一个小结论,即使是10^18级别的数据分解质因子也只会有二十几个不同的质因子而已,所以放心分解之后容斥,还有同样因为lcm(m,n)太大,所以最好分开分解然后set去重,最后也是因为lcm(m,n)太大,所以要二分找答案。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXM=25;
long long gcd(long long x,long long y)
{
return y==0? x:gcd(y,x%y);
}
long long n,m,k;
long long rec[33];
long long handle(long long x,int cnt)
{
long long ans=0;
long long k,p;
for (int i=0;i<cnt;i++)
{
if (rec[i]>x)
{
cnt=i;
break;
}
}
for (int i=1;i<(1<<cnt);i++)
{
p=1;
k=0;
for (int j=0;j<cnt;j++)
{
if (i&(1<<j))
{
k++;
p=p*rec[j];
}
}
if (k&1) ans=ans+x/p;
else ans=ans-x/p;
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
cin>>n>>m>>k;
long long tmpn=n;
long long tmpm=m;
set<long long > s1;
for (int i=2;i*i<=n;i++)
{
if (tmpn%i==0)
{
s1.insert(i);
while(tmpn%i==0) tmpn=tmpn/i;
}
}
if (tmpn!=1) s1.insert(tmpn);
for (int i=2;i*i<=m;i++)
{
if (tmpm%i==0)
{
s1.insert(i);
while(tmpm%i==0) tmpm=tmpm/i;
}
}
if (tmpm!=1) s1.insert(tmpm);
int cnt=0;
for (set<long long>::iterator it=s1.begin();it!=s1.end();it++)
rec[cnt++]=*it;
long long mid;
long long L=0;
long long R=0x3f3f3f3f3f3f3f3f;
while(L<=R)
{
mid=(L+R)>>1;
long long t=mid-handle(mid,cnt);
if (t<k) L=mid+1;
else R=mid-1;
}
printf("Case %d: %I64d\n",cas,L);
cas++;
}
return 0;
}