C.现在是,学术时间 (I)【2023牛客寒假算法基础集训营1】

C.现在是,学术时间 (I)

原题链接

题意

  • 每个教授i有1篇引用量为\(a_i\)的论文,求将论文重新分配后的最大H指数和

一位教授的H指数为使得"该教授发表的所有论文中,有至少H篇论文的引用量大于等于H"这一命题成立的最大的H。

思路1

  1. 如果不对论文进行分配,那么每篇被引用数量不为0的论文对H指数和的贡献都为1,最大H指数和为被引用数量不为0的论文数
  2. 由于最大H指数和不可能大于被引用数量不为0的论文数,因此不进行分配便是最优解
    “不要想学术不端,平平淡淡才是真”??

代码

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    int n;
    std::cin >> n;
    
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int a;
        std::cin >> a;
        ans += (a > 0);	//如果不为0,答案就+1
    }
    std::cout << ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int t;
    std::cin >> t;
    
    while (t--) {
        solve();
    }
    
    return 0;
}

思路2

  1. 因为论文顺序对原题不产生影响,则可以二分制造出序列的二段性后通过多次二分【每次r不变,因为每篇论文只能使用1次】每次找到符合条件的H指数再求和

代码

点击查看代码
#include<iostream>
using namespace std;

#define prep(i,a,b) for(int i = (a); i <= (b); i ++)
#define rrep(i,a,b) for(int i = (a); i >= (b); i --)

typedef long long LL;
const char nl = '\n';
int T, n, m;

const int N = 1e5 + 10;
int a[N];

bool check(int x){
	return a[x] >= n - x + 1;
}

void solve() {
	LL ans = 0;
	cin >> n;
	prep(i,1,n)cin >> a[i];
	sort(a + 1,a + n + 1);
	int l = 1,r = n;
	while(l < r){
		int mid = l + r >> 1;
		if(check(mid))r = mid;
		else l = mid + 1;
	}
	if(!check(l)){
		cout << 0 << nl;
		return;
	}
	else{
		ans += (n - l + 1);
		while(l > 1){	//当论文没有使用完时
			l = 1,r --,n = r;	//每次l复原,r--,n = r相当于分成若干个二分问题求总和
			while(l < r){
				int mid = l + r >> 1;
				if(check(mid))r = mid;
				else l = mid + 1;
			}
            if(!check(l))continue;
			else ans += (n - l + 1);
		}
	} 
	cout << ans << nl;

}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	cin >> T;
	while (T--) {
		solve();
	}

	return 0;
}

posted @ 2023-01-18 18:38  Keith-  阅读(31)  评论(0编辑  收藏  举报