YYHS-分数(二分+容斥)

题目描述

KJDH是个十分善于探索的孩子,有一天他把分子分母小于等于n的最简分数列在了纸上,他想找到这些分数里第k小的数,这对于KJDH来说当然是非常轻易,但是KJDH最近多了很多妹子,他还要去找妹子聊天,所以这个任务就交给你了。

输入

输入文件只有一行,两个数n,k,保证输入合法。

输出

输出文件包含两个用空格隔开的数,x,y,表示第k小的分数x/y。

样例输入

5 6 100 200

样例输出

3 5 6 91

提示

n=5时,有这些分数1/2,1/3,2/3,1/4,3/4,1/5,2/5,3/5,4/5。其中第6小的是3/5。


【数据规模与约定】

对于60%的数据,n<=2000

对于100%的数据,n<=50000
 

题解

这道题刚看到的时候完全没有头绪啊,打了暴力都感觉要T

后来听了正解发现是个比较巧妙的思想

我们首先二分一个小数

然后再找到最接近这个小数的分数——比如说二分出来的mid,你要找最接近的分数,我们可以枚举2~n为分母,这样我们可以直接算出分子了

找到分数后,我们需要计算小于等于这个分数的个数——那么我们同样也可以枚举2~n为分母,同样也可以算出分子,然后就是一个容斥啦

具体可以看一下代码

 1 #include<bits/stdc++.h>
 2 #define N 50005
 3 using namespace std;
 4 int n,k,sum;
 5 bool flag[N];
 6 vector<int>prime[N];
 7 struct node{
 8     int x,y;
 9 };
10 bool operator < (node x,node y){
11     return x.x*y.y<x.y*y.x;
12 }
13 void dfs(int now,int s,int num,int limit,int x){
14     if (now==prime[x].size()){
15         if (num&1) sum-=limit/s;
16                 else sum+=limit/s;
17         return;
18     }
19     dfs(now+1,s,num,limit,x);
20     dfs(now+1,s*prime[x][now],num+1,limit,x);
21 }
22 int calc(int x,int y){
23     sum=0;
24     dfs(0,1,0,x,y);
25     return sum;
26 }//计算<=x的数中与y的gcd值为1的个数 
27 int check(int x,int y){
28     int ans=0;
29     for (int i=2;i<=n;i++){
30         int s=i*x/y;
31         ans+=calc(s,i);
32     }
33     return ans;
34 }
35 node find(double x){
36     node s={0,1};
37     for (int i=2;i<=n;i++){
38         int y=(int)(x*i);
39         if (s<(node){y,i}) s=(node){y,i};
40     }
41     return s;
42 }
43 void pre(){
44     for (int i=2;i<=n;i++)
45         if (!flag[i])
46             for (int j=i;j<=n;j+=i)
47                 flag[j]=true,prime[j].push_back(i);
48 } 
49 int main(){
50     scanf("%d%d",&n,&k);
51     pre();
52     double l=0.0,r=1.0;//二分一个小数 
53     while (true){
54         double mid=(l+r)/2.0;
55         node s=find(mid);//查找离这个小数最接近的分数 
56         int num=check(s.x,s.y);//记录小于等于s的分数的个数 
57         if (num<k) l=mid; else
58         if (num>k) r=mid; else{
59             printf("%d %d
",s.x,s.y);
60             return 0;
61         }
62     }
63     return 0;
64 }
View Code
原文地址:https://www.cnblogs.com/zhuchenrui/p/7778980.html