CCF CSP真题复盘笔记

14 阅读3分钟

CCF CSP复盘

1. CSP 20A 检测点查询

题目链接:点击跳转 CCF 真题网站

  1. 题意概述:在所有点中找到最近的三个点,距离相同编号较小的视为更近

  2. 新学知识点:

    • map与multimap:

      1. 相同特性:

        • 自动排序(数据在插入时,会自动按照 Key(键) 的大小(默认从小到大)存放在树的特定位置。)
        • 查找速度快:时间复杂度为 O(logN)O(\log N)
      2. 区别:

        • map:

          1. 自动去重(键是唯一的,值可以重复).
          2. 支持[]赋值
        • multimap:

          1. multimap键允许重复,排序时键相同会按输入顺序排序(本题就用了)

          2. 不支持[]赋值,用insert插入,示例

            std::vector<int> j(n , 0);
            std::multimap<int,int> k;
            for(int i = 0; i <= n - 1; ++i){
            	j[i] = (m[i + 1].x - a) * (m[i + 1].x - a) +
                    (m[i + 1].y - b) * (m[i + 1].y - b); 
            	k.insert({j[i], i + 1});
            }
            
  3. 解题思路

    运用两点间的距离公式,用一个数组存储n个距离,利用multimap,以距离为键,对应编号为值.multimap的自动排序+编号较小的视为更近+算距离时是从小编号到大编号顺序计算,这样就输出multimap的前三项的值就是要找的最近的三个检测点编号.

  4. 完整代码

    时间复杂度:O(NlogN)O(N \log N)

#include <bits/stdc++.h>

struct zb{
	int x, y;
};

int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
    
int n, a, b;
std::cin >> n >> a >> b;
std::vector<zb> m(n + 1);
for(int i = 1; i <= n; ++i){
	std::cin >> m[i].x >> m[i].y;	
}
    
std::vector<int> j(n , 0);
std::multimap<int,int> k;
for(int i = 0; i <= n - 1; ++i){
	j[i] = (m[i + 1].x - a) * (m[i + 1].x - a) + (m[i + 1].y - b) * (m[i + 1].y - b); 
	k.insert({j[i], i + 1});
}
    
int count = 0;
for(const auto& pair : k){
	if(count >= 3) break;
	std::cout << pair.second << '\n';
	count++;
}

return 0;
}
  1. 反思

    假如说题目将编号较小的视为更近改为编号较大的视为更近,那就应该反过来计算距离.从n到1的顺序来计算

2.CSP 20B 风险人群筛查

题目链接:点击跳转 CCF 真题网站

  1. 题意概述:

    判断居民的关于时间的一系列坐标点是否在一个长宽都与坐标轴平行的矩形内

  2. 解题思路:

    输入一个居民坐标后,判定其是否在矩形内,如若在则增加count3,只要count3有一次>0了,那么就说明用户经过了城市,并且,为了避免重复计算,再用一个计数器g来控制经过人数count1只增加一次.如若某次居民不在城市范围内,则将count3重置为0,这样才能保证题目连续性的要求,这是此题的关键.当然为了避免重复计算,同样需要一个计数器f.

  3. 完整代码:

    时间复杂度:O(NT)O(NT)

    #include <bits/stdc++.h>
    
    struct zb{
    	int x,y;
    };
    
    int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, k , t, x1, y1, x2 ,y2;
    std::cin >> n >> k >> t >> x1 >> y1 >> x2 >> y2;
    std::vector<zb> z(2 *t + 1);
    
    int count1 = 0, count2 = 0;
    for(int i = 1; i <= n; ++i){
    	int count3 = 0;
    	int g = 0, f = 0;
    for(int j = 1; j <= t ; ++j){
    	std::cin >> z[j].x >> z[j].y;
    	if(z[j].x >= x1 && z[j].x <= x2 && z[j].y >= y1 && z[j].y <= y2){
    		count3++;
    	}
    	if(z[j].x < x1 || z[j].x > x2 || z[j].y < y1 || z[j].y > y2){
    		count3 = 0;
    	}
    	if(count3 > 0 && g == 0){
    		count1++;
    		g++;
    	}
    	if(count3 >= k && f == 0){
    		count2++;
    		f++;
    }	
    }
    }
    
    std::cout << count1 << '\n';
    std::cout << count2 << '\n';
    
    return 0;
    }
    
    
  4. 反思:

    这道题的不重复性与题目要求的连续性很关键