牛的学术圈 I

牛的学术圈 I

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

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

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

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

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

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

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

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

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

输入格式

输入的第一行包含 NL

第二行包含 N 个空格分隔的整数 c1,,cN

输出格式

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

数据范围

1N105,
0ci105,
0L105

输入样例1:

4 0
1 100 2 3

输出样例1:

2

样例1解释

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

输入样例2:

4 1
1 100 2 3

输出样例2:

3

样例2解释

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

 

解题思路

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

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

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

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

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

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

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

  证明一下双指针的正确性。如果h往后走,增大到h,假设g也往后走,增大到g,那么会有a[g]h,因为按照规定g对应的那个数是第一个大于等于h的,因此有a[g]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[h1]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 @   onlyblues  阅读(128)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示