数据结构与算法课程设计——CSP202203

CSP202203

01 未初始化警告

题目

​ n个赋值语句,判断每个右值出现时是否未被初始化。

  • 被初始化:当条赋值语句的右值为变量;右值在之前的赋值语句中作为左值出现过(不论那条语句的右值是否被初始化)。

标签

​ 模拟?

输入

​ 第一行输入两个整数n、k,分别代表变量的个数 和 赋值语句的个数。

​ 之后k行,每行输入两个整数 x i ,   y i x_i,~y_i xi, yi,代表赋值语句左、右值变量的下标。

输出

​ 输出一行,一个整数,代表n条赋值语句中左值未被初始化的语句条数。

数据范围

  • 50%的数据满足 0 < n , k ≤ 1000 0<n,k\le1000 0<n,k1000

  • 所有数据满足 0 < n , k ≤ 1 0 5 0<n,k\leq10^5 0<n,k105

  • 1 ≤ x i ≤ n ,   0 ≤ y i ≤ n 1\leq x_i\le n,~0\leq y_i\leq n 1xin, 0yin

思路

​ 开一个足够大的数组,记录每个变量是否初始化,然后统计未被初始化的语句的条数。

注意

  • 后k行输入为变量的下标,因此总范围为 [ 0 , n ] [0, n] [0,n]
  • 0为常量,没有未初始化的情况
  • 不考虑某变量第一次作为左值出现时,右值是否已被初始化

代码

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

const int N = 1e5+7;
bool vis[N];

int main() {
	int n, k;
	cin >> n >> k;
	int l, r, cnt = 0;
	vis[0] = true; 
	for (int i = 0; i < k; ++i) {
		cin >> l >> r;
		if (!vis[r]) cnt++;
		vis[l] = true;
	}
	cout << cnt;
	return 0;
} 

02 何以出游

题目

​ t时刻核酸检测,t+k时刻获得核酸检测结果。有n个地点,地点 i i i 需要有 [ t i − c i + 1 , t i ] [t_i-c_i+1, t_i] [tici+1,ti]时刻内的核酸证明,求能去多少景点。

标签

​ 差分;前缀和;区间计算。

输入

​ 第一行输入三个空格分隔的整数 n   m   k n~m~k n m k,分别代表景点个数、查询个数、等待核酸结果所需时间。

​ 接下来n行,每行输出两个整数 t i   c i t_i~c_i ti ci,分别代表景点最早进入时间,需要持有 c i c_i ci时间内的核酸检测结果。

​ 接下来m行,每行输入一个整数q,代表核酸检测时间。

输出

​ 输出m行,每行输出一个整数。

​ 对于每个查询,输出可以选择的景点个数。

数据范围

  • 见CSP网站

思路

​ 对于景点 ( t i ,   c i ) (t_i,~c_i) (ti, ci),需要持有 [ t i − c i + 1 , t i ] [t_i-c_i+1,t_i] [tici+1,ti]时刻内的核酸证明,即 t i − c i + 1 ≤ q + k ≤ t i t_i-c_i+1\leq q+k\leq t_i tici+1q+kti,只要统计 q + k q+k q+k在这样的区间内的个数。

  • 如何统计个数?
    • 对于每次查询,遍历所有景点,时间复杂度 O ( n m ) O(nm) O(nm)
    • 考虑到 t i 和 c i t_i和c_i tici都已经给定,在q+k范围不大的情况下,可以提前将每个q+k对应可去的景点个数求出。
      • 题目中q+k的数量级与n相同,在 1 0 5 10^5 105数量级
    • 使用区间端点表示左闭右开区间
      • 左端点记为1,右端点记为-1
      • 可以认为:进入区间时为1,离开区间时为-1
      • f ( x ) : = x 所在区间个数 , f(x):=x所在区间个数, f(x):=x所在区间个数, 这种表示方法下,x处的值为 f ( x ) − f ( x − 1 ) f(x)-f(x-1) f(x)f(x1),后向差分。
      • 如何计算 f ( x ) f(x) f(x)?使用有限积分,这里等价于前缀和。
      • 为什么使用左闭右开区间?
        • 良好的可加性: [ l e f t ,   m i d ) + [ m i d ,   r i g h t ) = [ l e f t , r i g h t ) [left,~mid)+[mid,~right)=[left,right) [left, mid)+[mid, right)=[left,right)
        • 容易计算元素个数: [ l e f t , r i g h t ) 中的元素个数 = r i g h t − l e f t [left,right)中的元素个数=right-left [left,right)中的元素个数=rightleft
        • 积分时的无穷小量在此不能省略,在使用分部积分法时,这种书写方式更简便。
      • 时间复杂度为 O ( n ) O(n) O(n)

注意

  • q+k的范围有3e5
  • 注意边界条件
  • 注意使用左闭右开区间

代码

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

const int N = 3e5+7;

int t[N], c[N], q;
int avail[N];

int main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	int n, m, k;
	cin >> n >> m >> k;
	int fir = 0;
	for (int i = 0; i < n; ++i) {
		cin >> t[i] >> c[i];
		avail[t[i]+1]--;
		if (t[i] - c[i] + 1 >= 0) {
			avail[t[i]-c[i]+1]++;
		} else {
			fir++;
		}
	}
	avail[0] += fir;
	for (int i = 1; i < N; ++i) {
		avail[i] += avail[i-1];
	}
	for (int i = 0; i < m; ++i) {
		cin >> q;
		q += k;
		cout << avail[q] << endl;
	}
	
	return 0;
} 

< N; ++i) {
avail[i] += avail[i-1];
}
for (int i = 0; i < m; ++i) {
cin >> q;
q += k;
cout << avail[q] << endl;
}

return 0;

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值