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
- 此处给定离散点,由于只需要判断各点之间的联系,因此仅需保存点的坐标而不必构造相应的图,不用考虑内存限制。
- 之后考虑各点之间的关系以及得分规则——各点之间的关系分为相邻以及对角线两种,且必须满足有4点相邻才考虑建立回收站并开始计分;对角线关系仅当确定放置回收站后开始作为计分标准,1个对角线垃圾点对应1分。
- 按照上述规则开始计分,每次计分对应关系的两点可同时进行加分,减少循环次数。
存储点坐标:考虑:结构体,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 赛题训练的主要内容,如果未能解决你的问题,请参考以下文章