csp 22-03-1 未初始化警告 &2 出行计划

未初始化警告
问题

给出若干条赋值语句的左右值的下标,判断哪些语句是没有初始化的。

思路

判断标准就是,右值的下标非0的时候,之前不曾在左侧出现。使用map,快速判断之前是否存在这个值。
使用一个map来记录左值的下标出现次数,每接收一对左、右值,当右值非常量且右值之前不在map中,结果加一,对于所有的都要左值加一。

#include <bits/stdc++.h>
using namespace std;

int main() {
	map<int, int> Left;
	int left, right;
	int n, k;
	cin >> n >> k;
	int ans = 0;
	for(int i = 0; i < k; i++) {
		cin >> left >> right;
		//非常量,且之前没出现过
		if(right != 0 && Left[right] == 0) {
			ans++;
		}
		Left[left]++;
	}
	cout << ans << endl;
	return 0;
}
出行计划
问题

有n个出行计划,(t,c)数据对,表示要进入该场所的时刻和该场所要求的核酸有效期。t1 时刻做了核酸,k个单位时间拿到核算报告,对于(t0,c0)场所,
t1 + k <= t0, t0 - (t1 + k) < c0,即到达该场所时,报告已经生效,且此时生效的时间小于场所的要求有效时间。对于n个出行计划,有m个时刻做核酸的选择,核酸生效的时间是k,求m个q各自能满足多少个出行计划。

思路

其实也可以暴力的方法,对于每个q遍历每个场所,看能否满足要求。
也搜索了优秀的方法。我先试一下暴力的方法。不出所料地错误。
在这里插入图片描述

70分
#include <bits/stdc++.h>

using namespace std;

int main(){
	int n, m, k;
	cin >> n >> m >> k;
	vector<vector<int> > sch(n,vector<int>(2));
	for(int i = 0; i < n; i++){
		cin >> sch[i][0] >> sch[i][1];
	}
	int q;
	int t;
	int count;
	for(int i = 0; i < m; i++){
		cin >> q;
		count = 0;
		t = q + k;//报告生效时刻 
		for(int j = 0; j < n; j++){
			if(sch[j][0] >= t && sch[j][0] <= t + sch[j][1] - 1){
				count++;
			}
		}
		cout << count << endl;
	}
	return 0;
}
50分

和70的区别在于没有存储结果,判断一个p输出一次,看来以后不用等到最后才输出,这样就能免去一次循环。

using namespace std;

int main(){
	int n, m, k;
	cin >> n >> m >> k;
	vector<vector<int> > sch(n,vector<int>(2));
	vector<int> ans(m,0);
	for(int i = 0; i < n; i++){
		cin >> sch[i][0] >> sch[i][1];
	}
	int q;
	int t;
	for(int i = 0; i < m; i++){
		cin >> q;
		t = q + k;//报告生效时刻 
		for(int j = 0; j < n; j++){
			if(sch[j][0] >= t && sch[j][0] <= t + sch[j][1] - 1){
				ans[i]++;
			}
		}
	}
	for(int i = 0; i < m; i++){
		if(ans[i]) cout << ans[i] << endl;
	}
	return 0;
}
优秀的思路

搜索了各种,又是使用差分数组,意识到自己还是没学会差分数组和前缀和。看大家的题解也觉得没看懂,在b站找了视频,终于理解了。
202203(第25次)CCF CSP真题202203-1,2讲解
之前我们是以核算报告的角度考虑,看每个场所能否进入,这次换做从场所的角度考虑,看这个场所允许哪些时间的报告进入。然后使用差分数组将这些报告的时间对应的值都加一,再求前缀和得到每个时间点的得分,最后根据输入的查询,直接得到满足几个场所。
每个场所的允许进入的核酸报告的时间区间是**(t - c, t],最早是报告刚好没有超时(也就是进入时刻 t 往前推 c 个小时),最晚是报告刚好生效。
因为时间都是整数,所以区间可以改成
[t - c - 1, t]**还要注意,区间的边界有效,右区间,肯定合法,但左区间
可能会小于0,所以要使规范,左区间最小为1。
借用视频的讲解图:
在这里插入图片描述

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 4e5+10;

int main()
{
	int n,m,k;
	int b[N];//差分数组
    cin >> n >> m >> k;
    int t, c;
    for(int i = 1; i <= n; i++)
    {
        cin >> t >> c;
        int left = t - c + 1;//定义左边界
        left = left > 0 ? left : 1;
        int right = t;//定义右边界
		//left ~ right之间的数都+1
		b[left]++;
		b[right+1]--;
    }
    //前缀和操作,得到各个点的数值
    for(int i = 1; i <= N; i++){
        b[i] = b[i-1] + b[i];
    }
    while(m--)
    {
        int x;
        cin >> x;
        cout << b[x+k] << endl;//直接得到x+k处的数值
    }
    return 0;
}
get

再次体验到差分数组和前缀和

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值