CCF-CSP 201912 赛题训练

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCF-CSP 201912 赛题训练相关的知识,希望对你有一定的参考价值。

这里写目录标题

【CCF CSP-20191201】报数

题意概述

甲乙丙丁决定玩一个报数的游戏。游戏规则为四个人从 1 开始轮流进行报数,但如果需要报出的数是 7 的倍数或含有数字 7 则直接跳过。此外大家约定,在总共报出了 n 个数后(不计入被跳过的)游戏结束。统计游戏过程中每个人各自跳过了几次。

输入输出格式

输入仅一行,包含一个正整数 n,表示报出了多少个数后游戏结束。

输出共四行,每行一个整数,依次表示甲乙丙丁四人在游戏过程中跳过的次数。

C++代码

常规代码Link

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

int n, skip[4];  // 作为甲乙丙丁循环

// 判断是否含7
bool judge(int x) 
    int t;
    while (x) 
        t = x%10;
        x /= 10;
        if (t == 7)
            return 1;
    
    return 0;


int main() 
    int cnt = 0, i = 1, turn = 0;
    cin >> n;
    while (cnt < n) 
        if (i%7==0 || judge(i)) 
            skip[turn]++;  // 对应人跳过++
         else 
            cnt++;  // 成功报数
        
        turn = (turn+1) % 4;
        i++;
    
    for (i = 0; i < 4; i++) 
        cout << skip[i] << endl;
    
    return 0;

大神代码

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

int main() 
    ll n;
    cin >> n;
    vector<ll> ans(4);  // 长度为4的数组
    for (ll i = 1; n > 0; i++) 
        if (i % 7 != 0 and to_string(i).find('7') == -1)   // 不包含7,返回-1
            n--;
         else 
            ans[(i-1)%4]++;
        
    
    for (ll i : ans) 
        cout << i << "\\n";

stoi("11"); 字符串变整型

【CCF CSP-20191201】回收站选址

11
9 10
10 10
11 10
12 10
13 10
11 9
11 8
12 9
10 9
10 11
12 11

0
2
1
0
0

  1. 此处给定离散点,由于只需要判断各点之间的联系,因此仅需保存点的坐标而不必构造相应的图,不用考虑内存限制。
  2. 之后考虑各点之间的关系以及得分规则——各点之间的关系分为相邻以及对角线两种,且必须满足有4点相邻才考虑建立回收站并开始计分;对角线关系仅当确定放置回收站后开始作为计分标准,1个对角线垃圾点对应1分。
  3. 按照上述规则开始计分,每次计分对应关系的两点可同时进行加分,减少循环次数。

存储点坐标:考虑:结构体,set,map等STL使用。

判断上下左右与对角线的点:

大神做法Link

inline bool nextto(node pos1, node pos2) 
	if(pos1.x==pos2.x && abs(pos1.y-pos2.y)==1)  // 横坐标相同判断纵坐标相差1
		return true;
	else if(pos1.y==pos2.y && abs(pos1.x-pos2.x)==1)  // 纵坐标相同判断横坐标相差1
		return true;
	return false;


inline bool diagonal(node pos1, node pos2) 
	if(abs(pos1.x-pos2.x)==1 && abs(pos1.y-pos2.y)==1)
		return true;
	return false;

存储垃圾坐标

//定义一个结构体,x,y,存放坐标,nearRubbish记录上下左右的垃圾数,score记录对角的垃圾数 
struct Rubbish 
	int x;
	int y;
	int nearRubbish = 0;
	int score = 0;
 rubbish[1001];
pair<int,int> p[n+1]; //存放垃圾点对应的坐标
map<pair<int,int>,bool> m;  //将垃圾点标记为true,用map绑定 

组合代码:Link

#include<bits/stdc++.h>
using namespace std;
struct Rubbish //定义一个结构体,x,y,存放坐标,nearRubbish记录上下左右的垃圾数,score记录对角的垃圾数 
	int x;
	int y;
	int nearRubbish = 0;
	int score = 0;
 rubbish[1001];

inline bool nextto(Rubbish pos1, Rubbish pos2) 
	if(pos1.x==pos2.x && abs(pos1.y-pos2.y)==1)  // 横坐标相同判断纵坐标相差1
		return true;
	else if(pos1.y==pos2.y && abs(pos1.x-pos2.x)==1)  // 纵坐标相同判断横坐标相差1
		return true;
	return false;


inline bool diagonal(Rubbish pos1, Rubbish pos2) 
	if(abs(pos1.x-pos2.x)==1 && abs(pos1.y-pos2.y)==1)
		return true;
	return false;


int main()
	int n;
	cin>>n;
	int scoreKind[5] = 0;  // 存放得分为0-4的回收站数,初始化0
	for(int i = 0; i < n; i++)
		cin>>rubbish[i].x>>rubbish[i].y;
	
    // 暴力判断每一个垃圾的情况
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
			if(nextto(rubbish[i], rubbish[j]))  
			//判断是否为回收站,如果上下左右都有垃圾那么nearRubbish在 退出循环时的值为4,即符合回收站的标准 
				rubbish[i].nearRubbish++;
			
			if(diagonal(rubbish[i], rubbish[j]))  
			//用score记录四角垃圾数,记录得分 
				rubbish[i].score++;
            
		
	
    for(int i = 0; i < n; i++)
        if(rubbish[i].nearRubbish == 4)
            //值为4符合回收站条件,接下来记录不同得分的回收站数目 
            scoreKind[rubbish[i].score]++;
        
    
    for(int i = 0; i < 5; i++)
        cout << scoreKind[i] << endl;
    
    return 0;
 
#include<iostream>
#include<map>   //map中键值对的构造需要引入pair,因此包含utility头文件 
int score[5]; //记录不同分数的选址个数,例如score[0]表示0分选址的个数 
using namespace std;
 
int main()
	int n;
	scanf("%d",&n); //输入垃圾点个数 
	pair<int,int> p[n+1]; //存放垃圾点对应的坐标
	map<pair<int,int>,bool> m;  //将垃圾点标记为true,用map绑定 
	for(int i=1;i<=n;i++) //循环输入垃圾点 
		int x,y;
		scanf("%d%d",&x,&y); //输入垃圾点坐标 
		p[i].first = x;  
		p[i].second = y;
		m[p[i]] = true;  //将该垃圾点标记为true 
	
	for(int i=1;i<=n;i++)//从第一个垃圾点开始检测 
		//垃圾点(x,y)的上、左、下、右处的坐标的x和y值 
		int upper_x = p[i].first;
		int upper_y = p[i].second-1;
		int down_x = p[i].first;
		int down_y = p[i].second+1;
		int left_x = p[i].first-1;
		int left_y = p[i].second;
		int right_x = p[i].first+1;
		int right_y = p[i].second;
		//垃圾点(x,y)的上、左、下、右处的坐标 
		pair<int,int> upper = make_pair(upper_x,upper_y);
		pair<int,int> down = make_pair(down_x,down_y);
		pair<int,int> left = make_pair(left_x,left_y);
		pair<int,int> right = make_pair(right_x,right_y); 
		//判断是否符合选址的条件 
		if(m[upper]&&m[down]&&m[left]&&m[right])
			//符合选址的条件后,再判断该选址(x,y)的分数
			//成为选址的垃圾点(x,y)的四个对角线位置的坐标的x,y值 
			//lu左上,ld左下,ru右上,rd右下
			int lu_x = p[i].first -1;
			int lu_y = p[i].second -1;
			int ld_x = p[i].first -1;
			int ld_y = p[i].second +1;
			int ru_x = p[i].first +1;
			int ru_y = p[i].second -1;
			int rd_x = p[i].first+1;
			int rd_y = p[i].second+1;
			//lu左上,ld左下,ru右上,rd右下
			pair<int,int> lu = make_pair(lu_x,lu_y);
			pair<int,int> ld = make_pair(ld_x,ld_y);
			pair<int,int> ru = make_pair(ru_x,ru_y);
			pair<int,int> rd = make_pair(rd_x,rd_y);
			//开始统计垃圾点(x,y)的得分 
			int count = 0;
			if(m[lu])  //左上位置的垃圾点是否标记为true 
				count++;
			
			if(m[ld])//左下位置的垃圾点是否标记为true
				count++;
			
			if(m[ru])//右上位置的垃圾点是否标记为true
				count++;
			
			if(m[rd])//右下位置的垃圾点是否标记为true
				count++;
			
			//每比较完一个符合条件的选址,将对应得分为count的选址个数加1 
			score[count]++;
		
	
	//循环输出得分为0、1、2、3、4 的回收站选址的个数 
	for(int i=0;i<=4;i++)
		cout<<score[i]<<endl;
	return 0;

很暴力,利用map存储pair点,之后判断该点上下左右坐标构成pair,判断是否在map中。Link

简洁牛逼的方法Link

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

const int N=1000;

pair<int, int> p[N];
const int CN = 4;
int cnt[CN+1] = 0;

int main() 
    int n;
    map<pair<int, int>, int> ps;
    cin >> n;
    for (int i = 0; i < n; i++) 
        int x, y;
        cin >> x >> y;   
        p[i] = make_pair(x, y);
        ps[p[i]] = 1;  // 该坐标赋值为1
     
    memset(cnt, 0, sizeof(cnt));
    for (int i = 0; i < n; i++) 
        int x = p[i].first;
        int y = p[i].second;
        if (ps[make_pair(x, y-1)] && ps[make_pair(x, y+1)] && ps[make_pair(x-1, y)] && ps[make_pair(x+1, y)])   // 判断四方向都在map中
            // 暴力统计对角线数字
            cnt[ps[make_pair(x-1, y-1)] + ps[make_pair(x-1, y+1)] + ps[make_pair(x+1, y-1)] + ps[make_pair(x+1, y+1)]]++;
        

    
    for (int i = 0; i <= CN; i++) 
        cout << cnt[i] << endl;
    
    return 0;

坐标值范围比较大,而且坐标有可能是负数,难以用矩阵来存储坐标点,所以使用稀疏矩阵来存储。用STL的map来存储坐标是最为简单的。

看不懂的代码Link

#include<cstdio>
#include<set>
using namespace std;

struct Point
	int x;
	int y;
	Point(int _x, int _y): x(_x), y(_y)
	bool operator < (const Point &rhs) const 
		if(x==rhs.x) return y<rhs.y;
		return x<rhs.x;
	
;

int n;
int ans[5];
set<Point> pts;

bool find(int x, int y)
	if(pts.find(Point(x, y))!=pts.end()) return true;
	return false;


int main(以上是关于CCF-CSP 201912 赛题训练的主要内容,如果未能解决你的问题,请参考以下文章

CCF-CSP 201604 赛题训练

CCF-CSP 201612 赛题训练

CCF-CSP 201609 赛题训练

CCF-CSP 201709 赛题训练

CCF-CSP 201703 赛题训练

CCF-CSP 202203 赛题训练