杭电多校第一场1007Meteor(类欧几里得&莫比乌斯反演&Stern-Brocot树&分数二分 )
题目大意
求分子分母均小于n且互素的第K小的数字
解题思路
AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long LL;
struct Frac{
LL son,mon;
Frac(LL sons,LL mons){
son=sons/__gcd(sons,mons);
mon=mons/__gcd(sons,mons);
}
Frac(){}
Frac friend operator+(Frac x,Frac y)
{
LL nmon=x.mon/__gcd(x.mon,y.mon)*y.mon;
LL nson=nmon/x.mon*x.son+nmon/y.mon*y.son;
LL g=__gcd(nmon,nson);
return Frac(nson/g,nmon/g);
}
Frac friend operator/(Frac x,LL y)
{
LL nmon=x.mon*y;
LL nson=x.son;
LL g=__gcd(nson,nmon);
return Frac(nson/g,nmon/g);
}
bool friend operator<=(Frac x,Frac y)
{
LL nmon=x.mon/__gcd(x.mon,y.mon)*y.mon;
LL sonx=nmon/x.mon*x.son,sony=nmon/y.mon*y.son;
return sonx<=sony;
}
};
#define LL __int128
long long Sum(LL n,LL a,LL b,LL c)
{
if(n<=0) return 0;
LL ans=0;
if(c<0)
{
LL t=(a-c-1)/a;
c+=a*t;
ans-=n*t;
}
if(b<0)
{
LL t=(a-1-b)/a;
b+=a*t;
ans-=(n+1)*n*t/2;
}
if(c/a>0||b/a>0)
{
ans+=(c/a)*n;ans+=(b/a)*n*(n+1)/2;
c%=a;b%=a;
}
LL newn=(b*n+c)/a;
ans+=newn*(n+1)-Sum(newn,b,a,-c+b-1);
return ans;
}
#undef LL
int n,k;
const int size=1e6+5;
int p[size];bool prime[size];
int mu[size];int tot=0;
int summu[size];
void init()
{
for(int i=1;i<size;i++) prime[i]=true;
mu[1]=1;
for(int i=2;i<size;i++)
{
if(prime[i])
{
p[++tot]=i;
mu[i]=-1;
}
for(int j=1;j<=tot&&p[j]*i<size;j++)
{
prime[i*p[j]]=false;
if(i%p[j]==0)
{
mu[i*p[j]]=0;
break ;
}
else mu[i*p[j]]=-mu[i];
}
}
summu[0]=0;
for(int i=1;i<size;i++) summu[i]=summu[i-1]+mu[i];
}
LL count(Frac f)
{
LL ans=0;
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
ans=ans+1LL*(summu[r]-summu[l-1])*Sum(n/l,f.mon,f.son,0);
}
return ans;
}
Frac SBtree(Frac up)
{
Frac L=Frac(0,1),R=Frac(1,0);
LL x=up.son,y=up.mon;
Frac mid(1,1);
Frac ans=Frac(1,1);
while(x!=y&&mid.son<=n&&mid.mon<=n)
{
// cout<<mid.son<<' '<<mid.mon<<endl;
if(mid.son*up.mon>mid.mon*up.son) ans=mid;
if(x<y)
{
R=mid;
mid=Frac(L.son+R.son,L.mon+R.mon);
y-=x;
}
else
{
L=mid;
mid=Frac(L.son+R.son,L.mon+R.mon);
x-=y;
}
}
return ans;
}
int32_t main()
{
int t;
init();
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld",&n,&k);
Frac l(0,1),r(1,1);
Frac ans(-1,-1);
for(int t=40;t--;)
{
Frac mid=(l+r)/2;
if(count(mid)<k)
{
ans=mid;
l=mid;
}else r=mid;
}
// cout<<ans.son<<' '<<ans.mon<<endl;
Frac fans=SBtree(ans);
printf("%lld/%lld\n",fans.son,fans.mon);
}
}
/*
5
4 6
5 1
9 9
3 4
7 11
*/
}
// cout<<ans.son<<’ '<<ans.mon<<endl;
Frac fans=SBtree(ans);
printf("%lld/%lld\n",fans.son,fans.mon);
}
}
/*
5
4 6
5 1
9 9
3 4
7 11
*/