第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;    
}

猜你喜欢

转载自www.cnblogs.com/0526yao/p/10488555.html