#P3506. 第1题-加权H指数
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 93
            Accepted: 25
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年8月30日-阿里淘天(算法岗)
                              
                      
          
 
- 
                        算法标签>贪心算法          
 
第1题-加权H指数
思路分析
核心思想:排序与贪心
这个问题的关键在于找到一个判定条件和 x 之间的关系。让我们定义一个函数 f(x)=(∑i s.t. a_i≥xwi)−x。我们就是要找使得 f(x)≥0 成立的最大的 x。
可以观察到,随着 x 的增大,满足条件 ai≥x 的论文数量会减少或不变,因此这些论文的权重之和 ∑wi 是一个非增函数。而 x 本身是严格递增的。所以,f(x) 是一个单调递减函数。这种单调性通常暗示我们可以使用二分查找来求解。
排序 + 遍历
- 
排序:总时间复杂度是 O(nlogR)。考虑到 R 可能达到 109,这个方法是可行的,但我们可以题目更深层的结构。我们关心的其实是当 x 变化时,哪些论文被包含在。如果 ai 相同,排序顺序不影响结果。
 - 
遍历与计算:i 和权重 wi 作为一个二元组 (ai,wi)。然后将这 n 个二元组按照引用次数 ai 从大到小进行排序排序后,我们得到一个新的序列 (a1′,w1′),(a2′,w2′),...,(an′,wn′),其中 a1′≥a2′≥...≥an′。 我们从 i=1 到 n 遍历这个排好序的序列,并维护一个当前已遍历论文的权重累加和
current_weight_sum。 当遍历到第 i 篇论文 (ai′,wi′) 时:- 
current_weight_sum表示的是引用次数排名前 i 的论文的权重之和。 - 
这些论文的引用次数都大于等于 ai′。
 - 
对于任何一个潜在的H指数 x≤ai′,这前 i 篇论文都满足 aj′≥x 的条件。因此,对于这样的 x,其权重和至少为
current_weight_sum。 - 
所以,在这一步,我们找到了一个满足条件的 x 的集合。为了让 x 尽可能大,它必须同时满足两个条件:
- x≤ai′ (因为我们只考虑了引用次数至少为 ai′ 的论文)
 - x≤ 
current_weight_sum。 
 
 - 
 - 
最终答案:我们在整个遍历过程中,不断更新并记录所有候选答案中的最大值。遍历结束后,这个最大值就是我们要求的加权H指数。
 
C++
#include <iostream>
#include <vector>
#include <algorithm>
// 使用结构体存储每篇论文的引用次数和权重
struct Paper {
    long long a, w;
};
// 自定义比较函数,用于按引用次数降序排序
bool comparePapers(const Paper& p1, const Paper& p2) {
    return p1.a > p2.a;
}
void solve() {
    int n;
    std::cin >> n;
    std::vector<Paper> papers(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> papers[i].a;
    }
    for (int i = 0; i < n; ++i) {
        std::cin >> papers[i].w;
    }
    // 按引用次数从大到小排序
    std::sort(papers.begin(), papers.end(), comparePapers);
    long long max_h = 0;
    long long current_weight_sum = 0;
    // 遍历排序后的论文
    for (int i = 0; i < n; ++i) {
        // 累加当前权重
        current_weight_sum += papers[i].w;
        // 计算当前候选的H指数
        // 候选值x需要满足 x <= a_i 和 x <= current_weight_sum
        // 我们取两者中的较小值,作为当前能达到的最大x
        long long candidate_h = std::min(papers[i].a, current_weight_sum);
        // 更新全局最大的H指数
        if (candidate_h > max_h) {
            max_h = candidate_h;
        }
    }
    std::cout << max_h << std::endl;
}
int main() {
    // 提高cin/cout效率
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    int t;
    std::cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
Python
import sys
def solve():
    """
    处理单组测试数据的函数
    """
    try:
        # 从标准输入读取数据
        n_str = sys.stdin.readline()
        if not n_str: return
        n = int(n_str)
        a = list(map(int, sys.stdin.readline().split()))
        w = list(map(int, sys.stdin.readline().split()))
    except (IOError, ValueError):
        return
    # 将论文的引用次数和权重打包成元组列表
    # papers[i] = (a_i, w_i)
    papers = list(zip(a, w))
    # 按引用次数 a_i 从大到小排序
    papers.sort(key=lambda x: x[0], reverse=True)
    max_h = 0
    current_weight_sum = 0
    # 遍历排序后的论文
    for citation, weight in papers:
        # 累加当前权重
        current_weight_sum += weight
        
        # 计算当前候选的H指数
        # 候选值x需要满足 x <= citation 和 x <= current_weight_sum
        # 我们取两者中的较小值,作为当前能达到的最大x
        candidate_h = min(citation, current_weight_sum)
        
        # 更新全局最大的H指数
        if candidate_h > max_h:
            max_h = candidate_h
            
    print(max_h)
def main():
    """
    主函数,处理多组测试数据
    """
    try:
        # 读取测试数据组数 T
        t_str = sys.stdin.readline()
        if not t_str: return
        t = int(t_str)
        for _ in range(t):
            solve()
    except (IOError, ValueError):
        return
if __name__ == "__main__":
    main()
Java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
    // 定义一个静态内部类来表示论文
    static class Paper {
        long a; // 引用次数
        long w; // 权重
        Paper(long a, long w) {
            this.a = a;
            this.w = w;
        }
    }
    // 处理单组测试数据的函数
    private static void solve(BufferedReader br) throws IOException {
        int n = Integer.parseInt(br.readLine());
        Paper[] papers = new Paper[n];
        
        // 读取引用次数
        StringTokenizer st_a = new StringTokenizer(br.readLine());
        // 读取权重
        StringTokenizer st_w = new StringTokenizer(br.readLine());
        for (int i = 0; i < n; i++) {
            long a = Long.parseLong(st_a.nextToken());
            long w = Long.parseLong(st_w.nextToken());
            papers[i] = new Paper(a, w);
        }
        // 使用Lambda表达式按引用次数从大到小排序
        Arrays.sort(papers, (p1, p2) -> Long.compare(p2.a, p1.a));
        long maxH = 0;
        long currentWeightSum = 0;
        // 遍历排序后的论文
        for (int i = 0; i < n; i++) {
            // 累加当前权重
            currentWeightSum += papers[i].w;
            
            // 计算当前候选的H指数
            // 候选值x需要满足 x <= a_i 和 x <= currentWeightSum
            // 我们取两者中的较小值,作为当前能达到的最大x
            long candidateH = Math.min(papers[i].a, currentWeightSum);
            // 更新全局最大的H指数
            if (candidateH > maxH) {
                maxH = candidateH;
            }
        }
        System.out.println(maxH);
    }
    public static void main(String[] args) throws IOException {
        // 使用BufferedReader以提高读取效率
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        // 读取测试数据组数 T
        int t = Integer.parseInt(br.readLine());
        while (t-- > 0) {
            solve(br);
        }
    }
}
        题目内容
给定一个长度为 n 的非负整数序列 {a1,a2,...,an} 以及对应的非负整数权重序列 {w1,w2,...,wn}。
其中,第 i 篇论文被引用 ai 次,具有权重 wi 。
定义“加权 H 指数"为最大的非负整数 x ,使得在所有被引用次数至少 x 的论文中,它们的权重之和至少为 x 。
请你计算并输出该加权 H 指数。
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≤T≤104) 代表数据组数,每组测试数据描述如下:
第一行输入一个整数 n(1≤n≤2×105) ,表示论文数量;
第二行输入 n 个整数 a1,a2,...,an(0≤ai≤109),其中 ai 表示第 i 篇论文的引用次数;
第三行输入 n 个整数 w1,w2,...,wn(0≤wi≤109) 其中 wi 表示第 i 篇论文的权重。
除此之外,保证单个测试文件的 n 之和不超过 2×105 。
输出描述
每组测试数据输出一行一个整数,表示加权 H 指数。
样例1
输入
1
5
5 3 1 4 2
1 2 1 3 2
输出
4