蓝桥杯C++大学B组一个月冲刺记录2024/3/4
规则:每日三题
1.牛的学术圈
由于对计算机科学的热爱,以及有朝一日成为 「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指数。
可以使用双指针
但我更喜欢二分
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int M = 1e5+10;
int p[M];
int n,k;
bool check(int mid){
int q = k;
int tot = 0;
for(int i = 1;i <= n;++i){
if(mid - p[i] == 1&&q != 0){
q--;
tot++;
}
if(p[i] >= mid) tot ++;
}
if(tot >= mid) return true;
else return false;
}
int main(){
cin >> n >> k;
int l = 0,r = 1e5;
for(int i = 1;i <= n;++i){
cin >> p[i];
}
while(l < r){
int mid = (l + r + 1)/2;
if(check(mid) == false) r = mid - 1;
else l = mid;
}
cout << l << endl;
return 0;
}
2.最长连续不重复子序列
给定一个长度为 n的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
双指针
#include<iostream>
#include<algorithm>
using namespace std;
const int M = 1e5+5;
int p[M],num[M];
int n;
int ans = -1;
int main(){
cin >> n;
for(int r = 1,l = 1;r <= n;++r){
cin >> p[r];
num[p[r]]++;
while(num[p[r]] > 1){
num[p[l]]--;
l++;
}
ans = max(r - l + 1,ans);
}
cout << ans << endl;
return 0;
}
3.数组元素的目标和
给定两个升序排序的有序数组 A和 B,以及一个目标值 x。
数组下标从 0开始。
请你求出满足 A[i]+B[j]=x的数对 (i,j)。
数据保证有唯一解。
二分做法
#include<iostream>
#include<cstdio>
using namespace std;
const int M = 1e5+10;
int a[M],b[M];
int n,m,k;
int find(int t){
int l = 1,r = n;
while(l < r){
int mid = (l + r + 1)/2;
if(a[mid] > t) r = mid - 1;
else l = mid;
}
if(a[l] == t) return l;
else return -1;
}
int main(){
cin >> n >> m >> k;
for(int i = 1;i <= n; ++i) cin >> a[i];
for(int j = 1;j <= m; ++j){
cin >> b[j];
int t = find(k - b[j]);
if(t != -1){
cout << t - 1 << ' ' << j - 1 << endl;
return 0;
}
}
return 0;
}
双指针做法
#include<iostream>
using namespace std;
const int N =1e5+10;
int a[N],b[N];
int main(){
int n,m,x;
cin >> n >> m >> x;
for(int i = 1;i <= n;++i) cin >> a[i];
for(int j = 1;j <= m;++j) cin >> b[j];
for(int i = 1,j=m;i<=n;++i){
while(j>=0&&a[i]+b[j] > x) j--;
if(a[i] + b[j] == x){
cout << i-1 <<' '<< j-1 << '\n';
break;
}
}
return 0;
}
4.判断子序列
给定一个长度为 n的整数序列 a1,a2,…,an以及一个长度为 m 的整数序列 b1,b2,…,bm。
请你判断 a序列是否为 b序列的子序列。
子序列指序列的一部分项按原有次序排列而得的序列,例如序列 {a1,a3,a5}是序列 {a1,a2,a3,a4,a5}的一个子序列。
双指针
#include<iostream>
#include<cstdio>
using namespace std;
const int M = 1e5+10;
int a[M],b[M];
int n,m;
int main(){
cin >> n >> m;
for(int i = 1;i <= n; ++i) cin >> a[i];
for(int j = 1;j <= m; ++j) cin >> b[j];
for(int l = 1, r = 1;r <= m; ++r){
if(a[l] == b[r]) l++;
if(l > n){
cout << "Yes" << endl;
return 0;
}
}
cout << "No" << endl;
return 0;
}
5.日志统计
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N
行。
其中每一行的格式是:ts id 表示在 ts时刻编号 id的帖子收到一个”赞”。
现在小明想统计有哪些帖子曾经是”热帖”。
如果一个帖子曾在任意一个长度为 D的时间段内收到不少于 K个赞,小明就认为这个帖子曾是”热帖”。
具体来说,如果存在某个时刻 T满足该帖在 [T,T+D)这段时间内(注意是左闭右开区间)收到不少于 K个赞,该帖就曾是”热帖”。
给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。
双指针
第一遍做的时候,用vector存数据,循环的是时间的区间,用 i,j 去记录加入的记录和删去的记录下标。但是vector< PII > 会出现段错误
#include<iostream>
#include<algorithm>
using namespace std;
const int M = 1e5+10;
typedef pair<int,int>PII;
PII p[M];
int res[M],st[M];
int n,d,k;
int main(){
cin >> n >> d >> k;
for(int i = 1;i<=n;++i){
cin >> p[i].first >> p[i].second;
}
sort(p + 1,p + n + 1);
for(int i = 1,j = 1;i <= n; ++i){
res[p[i].second] ++;
while(p[i].first - p[j].first >= d){
res[p[j].second] --;
j++;
}
if(res[p[i].second] >= k) st[p[i].second]++;
}
for(int i = 0;i <= 1e5;++i){
if(st[i] != 0) cout << i << endl;
}
return 0;
}