CCF-CSP 202006 赛题训练
Posted ZSYL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCF-CSP 202006 赛题训练相关的知识,希望对你有一定的参考价值。
【CCF CSP-20200601】线性分类器
题意概述
给出 n 个二维平面上的点,这些点可以分成 A、B 两类。给出 m 条直线,针对每条直线判断是否能将 A、B 两类点完全分隔开。
输入输出格式
输入共 n + m + 1 行。第一行包含用空格分隔的两个正整数 n 和 m,分别表示点和查询的个数。接下来 n 行,每行依次按横坐标 纵坐标 类别
的格式输入 n 个点的信息,其中坐标为整数,类别为一个大写英文字母 A 或 B。接下来 m 行,每行依次输入 m 条直线的信息,表示给定直线一般式 A+Bx+Cy=0 的三个参数 A、B、C。
输出共 m 行,每行输出一个字符串。第 j 行 ( 1 ≤ j ≤ m ) (1\\le j\\le m) (1≤j≤m)输出的字符串对应第 j 条直线的查询结果:如果给定直线可以完美分隔 A、B 两类点,则输出 Yes;否则输出 No。
数据规模
0 < n ≤ 10 3 , 0 < m ≤ 20 0<n \\le 10^3,0<m \\le 20 0<n≤103,0<m≤20
算法设计
如何判断两个点是否在直线的一侧呢?这里要用到一些简单的数学知识。对于一条直线 A x + B y + C = 0 Ax+By+C=0 Ax+By+C=0,如果点 ( x 0 , y 0 ) \\left(x_0,y_0\\right) (x0,y0)满足 A x 0 + B y 0 + C > 0 Ax_0+By_0+C>0 Ax0+By0+C>0,则点 ( x 0 , y 0 ) \\left(x_0,y_0\\right) (x0,y0)在该直线上方;如果点 ( x 0 , y 0 ) \\left(x_0,y_0\\right) (x0,y0)满足 A x 0 + B y 0 + C < 0 Ax_0+By_0+C<0 Ax0+By0+C<0,则点 ( x 0 , y 0 ) \\left(x_0,y_0\\right) (x0,y0)在该直线下方;如果点 ( x 0 , y 0 ) \\left(x_0,y_0\\right) (x0,y0)满足 A x 0 + B y 0 + C = 0 Ax_0+By_0+C=0 Ax0+By0+C=0,则点 ( x 0 , y 0 ) \\left(x_0,y_0\\right) (x0,y0)在该直线上。
由于题目保证不存在恰好落在直线上的点,因此我们无需考虑点落在直线上的情况。因此,如果两个点都落在直线上方或直线下方,那么这两个点一定在直线的一侧;反之,如果一个点落在直线上方,一个点落在直线下方,那么这两个点一定不在直线的一侧。
由于输入的点最多只有 1000 个,输入的直线最多也只有 20 条,因此我们可以针对输入的每条直线,暴力查找每一个同类的点是否位于该直线的一侧。算法的时间复杂度为 O ( m n ) O\\left(mn\\right) O(mn)。
C++代码
#include <bits/stdc++.h>
using namespace std;
using gg = long long;
int main()
ios::sync_with_stdio(false);
cin.tie(0);
gg ni, mi;
cin >> ni >> mi;
vector<vector<array<gg, 2>>> points(2); // array<int,2>是指一个由两个整数组成的数组,即int类型的数组,其中的元素个数为2。
gg xi, yi, ai, bi, ci;
string typei;
while (ni--)
cin >> xi >> yi >> typei;
points[typei[0] - 'A'].push_back(xi, yi);
while (mi--)
cin >> ai >> bi >> ci;
for (auto& p : points)
for (gg i = 1; i < p.size(); ++i)
if ((ai + bi * p[i][0] + ci * p[i][1] > 0) ^ (ai + bi * p[0][0] + ci * p[0][1] > 0))
cout << "No\\n";
goto loop;
cout << "Yes\\n";
loop:;
return 0;
将点的坐标代入直线方程,通过计算结果大于0还是小于0,判断点在直线的哪一侧。
#include <cstdio>
#include<iostream>
using namespace std;
int n, m;
int c0, c1, c2;
struct Node
int x, y;
char type;
node[1005];
int main()
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> node[i].x >> node[i].y;
getchar();
node[i].type = getchar();
// 判断二分类
for (int i = 0; i < m; i++)
cin >> c0 >> c1 >> c2;
int succ = 1;
int flagA = -1, flagB = -1;
for (int j = 0; j < n; j++)
int t = (c0+c1*node[j].x + c2*node[j].y > 0) ? 1 : 0; //
if (node[j].type == 'A')
if (flagA == -1)
flagA = t; // 出现在一侧
else if (flagA != t)
succ = 0;
break;
else if (node[j].type == 'B')
if (flagB == -1)
flagB = t;
else if (flagB != t)
succ = 0;break;
if (flagA == flagB)
succ = 0; break; // 不能在同一侧
string s = succ ? "Yes" : "No";
cout << s << endl;
return 0;
【CCF CSP-20200602】稀疏向量
题意概述
给出两个 n 维向量的稀疏向量表示,计算这两个向量的内积。所谓稀疏向量表示,就是指用(index value)
的格式(索引由 1 开始)表示一个向量在 index 维度上的值为 value,例如向量
v
⃗
=
(
0
,
0
,
0
,
5
,
0
,
0
,
−
3
,
0
,
0
,
1
)
\\vecv=\\left(0,0,0,5,0,0,-3,0,0,1\\right)
v=(0,0,0,5,0,0,−3,0,0,1),就可以表示成
v
⃗
=
[
(
4
,
5
)
,
(
7
,
−
3
)
,
(
10
,
1
)
]
\\vecv=\\left[\\left(4,5\\right),\\left(7,-3\\right),\\left(10,1\\right)\\right]
v=[(4,5),(7,−3),(10,1)]。
输入输出格式
输入的第一行包含用空格分隔的三个正整数 n、a 和 b,其中 n 表示向量 u 和 v 的维数,a 和 b 分别表示两个向量所含非零值的个数。接下来 a 行,每行按index value
的格式输入向量 u 的稀疏表示。接下来 b 行,每行按index value
的格式输入向量 v 的稀疏表示。注意 index 由 1 开始。
输出一个整数,表示向量 u 和向量 v 的内积。
数据规模
n ≤ 10 9 , 0 < a , b < n , 0 < a , b ≤ 5 × 10 5 n\\le 10^9,0<a,b<n,0<a,b\\le 5 \\times10^5 n≤109,0<a,b<n,0<a,b≤5×105
算法设计
由于 n 最大为
10
9
10^9
109,无法直接开辟一个数组。可以先用 unordered_map
将向量 u 的索引和值对应存储起来。读取向量 v 的稀疏表示时,直接将其与向量 u 对应索引位置的值的乘积加和,最后输出结果即可。
10 3 4
4 5
7 -3
10 1
1 10
4 20
5 30
7 40
-20
样例解释
u = (0, 0, 0, 5, 0, 0, -3, 0, 0, 1)
v = (10, 0, 0, 20, 30, 0, 40, 0,0, 0)
u · v = 5 × 20 + (-3) × 40 = 20
C++代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a, b;
long long ans; // 使用long long
vector<pair<int, int>> u, v;
int main()
cin >> n >> a >> b;
int id, val;
for (int i = 0; i < a; i++)
cin >> id >> val;
u.push_back(id, val);
for (int i = 0; i < b; i++)
cin >> id >> val;
v.push_back(id, val);
int i = 0, j = 0;
// 类似归并排序的内味儿,总有一个先到末尾
while (i < a && j < b)
if (u[i].first == v[j].first)
ans += u[i].second * v[j].second;
i++;
j++;
else以上是关于CCF-CSP 202006 赛题训练的主要内容,如果未能解决你的问题,请参考以下文章