第k小分数(二分值)
//时间限制:10000ms //单点时限:1000ms //内存限制:256MB //描述 //给定N个不同的质数P1, P2, … PN。用它们作为分目可以组成(P1-1) + (P2-1) + … (PN-1)个分数: // //1/P1, 2/P1, 3/P1, …, P1-1/P1, 1/P2, 2/P2, 3/P2, … P2-1/P2, … 1/PN, 2/PN, … PN-1/PN // //请帮助小Ho求出其中第K小的分数。 // //输入 //第一行包含两个整数N和L。 // //以下N行每行包含一个质数Pi。 // //对于70%的数据,1 ≤ N ≤ 100, 1 ≤ K ≤ 1000000, 2 ≤ Pi ≤ 100000 // //对于100%的数据, 1 ≤ N ≤ 1000, 1 ≤ K ≤ 1000000000, 2 ≤ Pi ≤ 1000000000 // //输出 //输出一个分数表示答案 // //样例输入 //3 4 //2 //3 //5 //样例输出 //1/2 //题解: //由于p是质数,所以每个分数都不可约分,由于对于每一个1/P1, 2/P1, 3/P1, …, //P1-1/P1序列都是递增,我们可以二分答案,算出小于等于二分答案的数有多少个, //当个数等于k时即二分答案接近要求的答案,记录最接近的分子和分母,即为答案 #include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <iostream> #include <algorithm> using namespace std; int main() { int n, k; while(scanf("%d%d",&n,&k)==2){ long long f[1005]; memset(f,0,sizeof(f)); for( int i = 1; i <= n; i++ ) { scanf("%lld", &f[i] ); } long long zz , ff; double l = 0, r = 1.0, mid; while(true){ mid = (r+l)/2.0; long long ans = 0; zz = ff = -1; for( int i = 1; i <= n; i++ ) { long long x = mid*f[i]; ans += x; if( zz == -1 ) { zz = x; ff = f[i]; } if((long long)f[i]*zz < (long long)x*ff){ zz = x; ff = f[i]; } // cout << zz << "/" << ff<<endl; } // cout<<"ans = "<<ans<<endl; if( ans == k ) break; if( ans > k ) r = mid; else l = mid; } cout << zz << "/" << ff<<endl; } return 0; }