2024AcWing蓝桥杯集训·每日一题-双指针

1.[AcWing3745.牛的学术圈 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

解题思路

降序排序,找到最大的 i 使得 cii,此时不额外引用(每个文章最多被引用一次)的最大的 h 即为 i,每个数最多只能加 1,所以 h 指数最大只能是 h+1。因此需要取部分数进行加一操作,首先是 ch+1,如果 ch+1<h,最多等于 h,则不会出现 ch+1=h+1 的情况,其后面的数也是一样,因此此情况最多为 h。否则 ch+1=h(根据前面 h 的初步确定 ch+1<=hch+1<h 不成立),那么由此往前找 ci=h 的进行加一,若个数小于等于 L 则指数增加为 h+1,否则仍为 h

C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;

int n, L;
int c[N];

int main() {
    scanf("%d%d", &n, &L);
    for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
    sort(c + 1, c + n + 1);
    reverse(c + 1, c + n + 1);
    int h = 0;
    for (int i = 1; i <= n; i++) {
        if (c[i] >= i) h = i;
        else break;
    }
    if (c[h + 1] < h) {
        printf("%d\n", h);
        return 0;
    }
    int cnt = 0;
    for (int i = 1; i <= h + 1; i++)
        if (c[i] == h)
            cnt++;
    if (cnt <= L)
        printf("%d\n", h + 1);
    else
        printf("%d\n", h);
    /* 双指针做法
    // 关于 h
    // 1. 最小值大于等于 h-1
    // 2. h-1 的个数小于等于 L
    int res = 0;
    for (int i = 1, j = n; i <= n; i++) {
        while (j && c[j] < i) j--;
        if (c[i] >= i - 1 && i - j <= L)
            res = i;
    }
    cout << res << endl;
    */
    return 0;
}

2.[AcWing1238.日志统计]

题目描述

小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N 行。
其中每一行的格式是:

ts id

表示在 ts 时刻编号 id 的帖子收到一个“赞”。现在小明想统计有哪些帖子曾经是“热帖”。如果一个帖子曾在任意一个长度为 D 的时间段内收到不少于 K 个赞,小明就认为这个帖子曾是“热帖”。

具体来说,如果存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是“热帖”。

给定日志,请你帮助小明统计出所有曾是“热帖”的帖子编号。

输入格式

第一行包含三个整数 N,D,K
以下 N 行每行一条日志,包含两个整数 tsid

输出格式

按从小到大的顺序输出热帖 id
每个 id 占一行。

数据范围

1KN105,
0ts,id105,
1D10000

输入样例
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
输出样例
1
3
解题思路

双指针。使用数对数组按照时间排序,在时间区间内维护 cnt 数组统计点赞次数。

C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef pair<int, int> PII;
#define ts first
#define id second

int n, D, K;
PII q[N];
bool st[N];
int cnt[N];

int main() {
    scanf("%d%d%d", &n, &D, &K);
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &q[i].ts, &q[i].id);
    sort(q + 1, q + n + 1);
    for (int i = 1, j = 1; i <= n; i++) { // i 是右指针 j 是左指针
        cnt[q[i].id]++; // 点赞次数+1
        while (q[i].ts - q[j].ts >= D) { // 保证时间区间
            cnt[q[j].id]--;
            j++;
        }
        if (cnt[q[i].id] >= K) st[q[i].id] = true;
    }
    for (int i = 0; i < N; i++)
        if (st[i])
            printf("%d\n", i);
    return 0;
}
posted @   Cocoicobird  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示