题目描述
Let's denote as L(x,p)L(x,p) an infinite sequence of integers yy such that gcd(p,y)=1gcd(p,y)=1 and y>xy>x (where gcdgcd is the greatest common divisor of two integer numbers), sorted in ascending order. The elements of L(x,p)L(x,p) are 11 -indexed; for example, 99 , 1313 and 1515 are the first, the second and the third elements of L(7,22)L(7,22) , respectively.
You have to process tt queries. Each query is denoted by three integers xx , pp and kk , and the answer to this query is kk-th element of L(x,p)L(x,p) .
输入输出格式
输入格式:
The first line contains one integer tt ( 1<=t<=300001<=t<=30000 ) — the number of queries to process.
Then tt lines follow. ii -th line contains three integers xx , pp and kk for ii -th query ( 1<=x,p,k<=10^{6}1<=x,p,k<=106 ).
输出格式:
Print tt integers, where ii -th integer is the answer to ii -th query.
输入输出样例
187 87 139 128 141
二分+容斥就ojbk了,考虑到<=10^6的数最多有10种质因子,我们就把p质因子分解一下,然后二分第k大的满足条件的数y是多少。
需要写一个用来计算前i个数中有多少数与p互质的函数get,那么当get(y)-get(x)>=k时,更新答案并调整右边界;否则调整左边界。
之所以这么做的原因是,我们需要找到get(y)-get(x)==k的最小的y,这个y才是要求的第k大的与p互质的数。
还有不是很明白为什么时限是5s(虽然看洛谷上好多人都是卡着时限过的),反正我最慢的一个点也才跑了300+ms,如图
可能是因为我加了一些预处理来优化计算过程吧hhhh,请不要把我想成用循环展开什么缓存dark技巧来卡常的毒瘤人士(虽然迫不得已的时候会用一些dark卡常技巧)
#include<bits/stdc++.h> #define ll long long #define maxn 1000005 using namespace std; int num,d[66],f[2066],jc[2066]; int T,n,a,p,k,ci[30]; int l,r,mid,ans,now; const int inf=1000000000; inline void dvd(){ num=0,n=sqrt(p+0.5); for(int i=2;i<=n;i++) if(!(p%i)){ d[++num]=i; while(!(p%i)) p/=i; if(p==1) break; } if(p!=1) d[++num]=p; for(int S=0;S<ci[num];S++){ jc[S]=1; for(int j=0;j<num;j++) if(ci[j]&S) jc[S]*=d[j+1]; } } //<=x的数中有多少与p互质 inline int get(int x){ int an=0; for(int s=0;s<ci[num];s++) an+=f[s]*(x/jc[s]); return an; } int main(){ ci[0]=1; for(int i=1;i<=20;i++) ci[i]=ci[i-1]<<1; f[0]=1; for(int i=1;i<=2055;i++) f[i]=-f[i^(i&-i)]; scanf("%d",&T); while(T--){ scanf("%d%d%d",&a,&p,&k); dvd(); l=a+1,r=inf,now=get(a); while(l<=r){ mid=l+r>>1; if(get(mid)-now<k) l=mid+1; else ans=mid,r=mid-1; } printf("%d\n",ans); } return 0; }