牛的学术圈 I

牛的学术圈 I

由于对计算机科学的热爱,以及有朝一日成为 「Bessie 博士」的诱惑,奶牛 Bessie 开始攻读计算机科学博士学位。

经过一段时间的学术研究,她已经发表了 $N$ 篇论文,并且她的第 $i$ 篇论文得到了来自其他研究文献的 $c_{i}$ 次引用。

Bessie 听说学术成就可以用 $h$ 指数来衡量。

$h$ 指数等于使得研究员有至少 $h$ 篇引用次数不少于 $h$ 的论文的最大整数 $h$。

例如,如果一名研究员有 $4$ 篇论文,引用次数分别为 $\left( {1,100,2,3} \right)$,则 $h$ 指数为 $2$,然而若引用次数为 $\left( {1,100,3,3} \right)$ 则 $h$ 指数将会是 $3$。

为了提升她的 $h$ 指数,Bessie 计划写一篇综述,并引用一些她曾经写过的论文。

由于页数限制,她至多可以在这篇综述中引用 L 篇论文,并且她只能引用每篇她的论文至多一次

请帮助 Bessie 求出在写完这篇综述后她可以达到的最大 $h$ 指数。

注意 Bessie 的导师可能会告知她纯粹为了提升 $h$ 指数而写综述存在违反学术道德的嫌疑;我们不建议其他学者模仿 Bessie 的行为。

输入格式

输入的第一行包含 $N$ 和 $L$。

第二行包含 $N$ 个空格分隔的整数 $c_{1}, \dots ,c_{N}$。

输出格式

输出写完综述后 Bessie 可以达到的最大 $h$ 指数。

数据范围

$1 \leq N \leq {10}^{5}$,
$0 \leq c_{i} \leq {10}^{5}$,
$0 \leq L \leq {10}^{5}$

输入样例1:

4 0
1 100 2 3

输出样例1:

2

样例1解释

Bessie 不能引用任何她曾经写过的论文。上文中提到,$\left( {1,100,2,3} \right)$ 的 $h$ 指数为 $2$。

输入样例2:

4 1
1 100 2 3

输出样例2:

3

样例2解释

如果 Bessie 引用她的第三篇论文,引用数会变为 $\left( {1,100,3,3} \right)$。上文中提到,这一引用数的 $h$ 指数为 $3$。

 

解题思路

  这是一个关于$h$指数的问题。$h$的含义为至少$h$篇文章,被引用的次数大于等于$h$,满足这个条件的所有$h$中最大的那个数。

  求$h$指数的方法是先将这个序列从大到小进行排序,然后从小到大枚举$h$,如果前$h$篇文章被引用次数都大于等于$h$,那么这个$h$是满足条件的。

  在这题中可以选择让其中某些文章增加一次的引用次数,问我们在这个条件下$h$指数最大是多少。

  一样先将文章从大到小排序,然后从小到大枚举$h$,这个$h$要成立要满足下面两个条件:

  • 由于我们选择的是前$h$篇文章,这$h$篇文章是所有文章里最大的$h$篇,因此这$h$篇中的最小值要大于等于$h - 1$。
  • 这$h$篇文章中,引用次数为$h - 1$的文章数量应该小于等于$L$。

  由于$h$是从小到大枚举,序列是单调递减的,因此最小值就是第$h$个数,即$a \left[ h \right]$,因此第一个条件就是要满足$a \left[ h \right] \geq h - 1$。

  对于第二个条件,我们就是要找到$h$左边第一个大于等于$h$的数,假设这个数的下标为$g$。由于$h$单调递增,序列单调递减,每次$h$增加,意味着我们要找的$h$左边第一个大于等于$h$的数也要增加,即$g$应该是向左移动的,即$g$是单调减少的。因此有当$h$单调递增,$g$会单调递减,可以用双指针来解决。

  证明一下双指针的正确性。如果$h$往后走,增大到$h'$,假设$g$也往后走,增大到$g'$,那么会有$a \left[ {g'} \right] \geq h'$,因为按照规定$g'$对应的那个数是第一个大于等于$h'$的,因此有$a \left[ {g'} \right] \geq h' > h$,又因为对于$h$而言,第一个大于等于$h$的数应该在$g$这个位置上,但选择$g'$也满足且更靠近$h$,因此就矛盾了。因此$g$是单调递减的。

  AC代码如下:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int N = 1e5 + 10;
 6 
 7 int a[N];
 8 
 9 int main() {
10     int n, m;
11     scanf("%d %d", &n, &m);
12     for (int i = 1; i <= n; i++) {
13         scanf("%d", a + i);
14     }
15     
16     sort(a + 1, a + n + 1, greater<int>());
17     
18     int ret = 0;
19     for (int i = 1, j = n; i <= n; i++) {
20         while (j && a[j] <= i - 1) {    // 找到第一个大于等于h的数
21             j--;
22         }
23         if (a[i] >= i - 1 && i - j <= m) ret = i;   // 要满足两个条件
24     }
25     
26     printf("%d", ret);
27     
28     return 0;
29 }

  对于第二个条件,还可以开一个数组来记录每篇文章引用次数的个数,直接查是否满足$cnt \left[ {h - 1} \right] \leq L$这个条件就可以了。

  AC代码如下:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int N = 1e5 + 10;
 6 
 7 int a[N], cnt[N];
 8 
 9 int main() {
10     int n, m;
11     scanf("%d %d", &n, &m);
12     for (int i = 1; i <= n; i++) {
13         scanf("%d", a + i);
14     }
15     
16     sort(a + 1, a + n + 1, greater<int>());
17     
18     int ret = 0;
19     for (int i = 1; i <= n; i++) {
20         cnt[a[i]]++;
21         if (a[i] >= i - 1 && cnt[i - 1] <= m) ret = i;
22     }
23     
24     printf("%d", ret);
25     
26     return 0;
27 }

 

参考资料

  AcWing 3745. 牛的学术圈 I(春季每日一题2022):https://www.acwing.com/video/3736/

posted @ 2022-03-20 09:38  onlyblues  阅读(116)  评论(0编辑  收藏  举报
Web Analytics