CCF-CSP 202309-2 坐标变换(其二)
😸题目要求
对于平面直角坐标系上的坐标 ( x , y ) (x,y) (x,y),小 P 定义了如下两种操作:
- 拉伸 k k k 倍:横坐标 x x x 变为 k x kx kx,纵坐标 y y y 变为 k y ky ky;
- 旋转 θ \theta θ:将坐标 ( x , y ) (x,y) (x,y) 绕坐标原点 ( 0 , 0 ) (0,0) (0,0) 逆时针旋转 θ \theta θ 弧度 ( 0 ≤ θ < 2 π ) (0 \leq \theta < 2\pi) (0≤θ<2π)。易知旋转后的横坐标为 x c o s θ − y s i n θ xcos\theta-ysin\theta xcosθ−ysinθ,纵坐标为 x s i n θ + y c o s θ xsin\theta+ycos\theta xsinθ+ycosθ。
设定好了包含 n n n 个操作的序列 ( t 1 , t 2 , ⋅ ⋅ ⋅ t n ) (t_1,t_2,···t_n) (t1,t2,⋅⋅⋅tn) 后,小 P 又定义了如下查询:
- i j x y i \quad j \quad x \quad y ijxy:坐标 ( x , y ) (x,y) (x,y) 经过操作 t i , ⋅ ⋅ ⋅ , t j ( 1 ≤ i ≤ j ≤ n ) t_i,···,t_j(1 \leq i \leq j \leq n) ti,⋅⋅⋅,tj(1≤i≤j≤n) 后的新坐标。
对于给定的操作序列,试计算 m m m 个查询的结果。
🐈⬛输入格式
从标准输入读入数据。
输入共
n
+
m
+
1
n+m+1
n+m+1 行。
输入的第一行包含空格分隔的两个正整数
n
n
n 和
m
m
m,分别表示操作和初始坐标个数。
接下来
n
n
n 行依次输入
n
n
n 个操作,每行包含空格分隔的一个整数(操作类型)和一个实数 (
k
k
k 或
θ
\theta
θ),形如
1
k
1 \quad k
1k(表示拉伸
k
k
k 倍)或
2
θ
2 \quad \theta
2θ(表示旋转
θ
\theta
θ)。
接下来
m
m
m 行依次输入
m
m
m 个查询,每行包含空格分隔的四个整数
i
i
i、
j
j
j、
x
x
x 和
y
y
y,含义如前文所述。
🐈⬛输出格式
输出到标准输出中。
输出共
m
m
m 行,每行包含空格分隔的两个实数,表示对应查询的结果。
🐈⬛样例输入
10 5
2 0.59
2 4.956
1 0.997
1 1.364
1 1.242
1 0.82
2 2.824
1 0.716
2 0.178
2 4.094
1 6 -953188 -946637
1 9 969538 848081
4 7 -114758 522223
1 9 -535079 601597
8 8 159430 -511187
🐈⬛样例输出
-1858706.758 -83259.993
-1261428.46 201113.678
-75099.123 -738950.159
-119179.897 -789457.532
114151.88 -366009.892
🐈⬛样例说明
第五个查询仅对输入坐标使用了操作八:拉伸
0.716
0.716
0.716 倍。
横坐标:
159430
×
0.716
=
114151.88
159430×0.716=114151.88
159430×0.716=114151.88
纵坐标:
−
511187
×
0.716
=
−
366009.892
-511187×0.716=-366009.892
−511187×0.716=−366009.892
由于具体计算方式不同,程序输出结果可能与真实值有微小差异,样例输出仅保留了三位小数。
🐈⬛评测用例规模与约定
80% 的测试数据满足:
n
,
m
≤
1000
n,m \leq 1000
n,m≤1000
全部的测试数据满足:
- n , m ≤ 100000 n,m \leq 100000 n,m≤100000;
- 输入的坐标均为整数且绝对值不超过 1000000 1000000 1000000;
- 单个拉伸操作的系数 k ∈ [ 0.5 , 2 ] k \in [0.5,2] k∈[0.5,2];
- 任意操作区间 t i , ⋅ ⋅ ⋅ , t j ( 1 ≤ i ≤ j ≤ n ) t_i,···,t_j(1 \leq i \leq j \leq n) ti,⋅⋅⋅,tj(1≤i≤j≤n) 内拉伸系数 k k k 的乘积在 [ 0.001 , 1000 ] [0.001,1000] [0.001,1000] 范围内。
🐈⬛评分方式
如果你输出的浮点数与参考结果相比,满足绝对误差不大于 0.1 0.1 0.1,则该测试点满分,否则不得分。
🐈⬛提示
- C/C++:建议使用 double 类型存储浮点数,并使用
scanf("%lf", &x);
进行输入,printf("%f", x);
输出,也可以使用cin
和cout
输入输出浮点数;#include <math.h>
后可使用三角函数cos()
和sin()
。 - Python:直接使用
print(x)
即可输出浮点数 x;from math import cos, sin
后可使用相应三角函数。 - Java:建议使用 double 类型存储浮点数,可以使用
System.out.print(x);
进行输出;可使用Math.cos()
和Math.sin()
调用三角函数。
😸问题解决
🐈80分代码(含逐行代码解释)
因为尝试不使用STL库,所以进行了两层循环导致时间复杂度变高从而运行超时只有80分,若使用STL库则可轻易达到满分,网上可以查到很多满分解答。
🍭C++
#include<bits/stdc++.h>
using namespace std;
struct operation{
//定义操作结构体
int type; //操作种类k或θ
double value; //对应的数值
}op[1000001];
struct coordinate{
//定义坐标结构体
int i; //操作起始
int j; //操作终止
double x; //横坐标
double y; //纵坐标
}coor[1000001];
int main(){
int n, m;
cin >> n >> m; //输入操作和查询个数
for(int t = 1; t <= n; t++)
{
cin >> op[t].type >> op[t].value; //输入操作编号以及对应的数值k或者θ
}
for(int t = 1; t <= m; t++){
cin >> coor[t].i >> coor[t].j >> coor[t].x >> coor[t].y; //输入操作范围以及坐标
}
double xx, yy; //用来存储横纵坐标的中间变量,注意是双精度类型
for(int t = 1; t <= m; t++){ //大循环表示遍历m个坐标
for(int p = coor[t].i; p <= coor[t].j; p++){ //小循环表示对每个坐标进行p个变换操作
if(op[p].type == 1){ //1对应的是k,直接乘积即可
xx = coor[t].x * op[p].value;
yy = coor[t].y * op[p].value;
}
else if(op[p].type == 2){ //2对应的是θ,采用题目中的公式
xx = coor[t].x * cos(op[p].value) - coor[t].y * sin(op[p].value);
yy = coor[t].x * sin(op[p].value) + coor[t].y * cos(op[p].value);
}
coor[t].x = xx; //更新横坐标变换后的结果
coor[t].y = yy; //更新纵坐标变换后的结果
}
cout << fixed << setprecision(3) << xx << " " << yy << "\n";
//等价于 printf("%.3f %.3f\n", coor[t].x, coor[t].y);
}
}
🍭Python
#代码逻辑与C++完全一样,不再一一赘述
import math
class Operation:
def __init__(self, type_, value):
self.type = type_
self.value = value
class Coordinate:
def __init__(self, i, j, x, y):
self.i = i
self.j = j
self.x = x
self.y = y
n, m = map(int, input().split())
op = [None] * (n + 1)
for t in range(1, n + 1):
type_, value = map(float, input().split())
op[t] = Operation(int(type_), value)
coor = [None] * (m + 1)
for t in range(1, m + 1):
i, j, x, y = map(float, input().split())
coor[t] = Coordinate(int(i), int(j), x, y)
for t in range(1, m + 1):
for p in range(coor[t].i, coor[t].j + 1):
if op[p].type == 1:
xx = coor[t].x * op[p].value
yy = coor[t].y * op[p].value
elif op[p].type == 2:
xx = coor[t].x * math.cos(op[p].value) - coor[t].y * math.sin(op[p].value)
yy = coor[t].x * math.sin(op[p].value) + coor[t].y * math.cos(op[p].value)
coor[t].x = xx
coor[t].y = yy
print('{:.3f} {:.3f}'.format(xx, yy))
🐈场景拓展
本题是对上一道题的一个进阶和补充,主要目的在于坐标变换,它可以根据给定的操作类型和数值对坐标进行变换。主要应用场景包括但不限于:
- 图形变换:可以通过修改操作类型和数值来实现平移、旋转、缩放等图形变换操作。
- 数据分析与可视化:在数据分析和可视化领域,经常需要对数据进行坐标变换,以便更好地理解和展示数据。
- 物体运动模拟:在物理模拟和游戏开发中,需要对物体进行坐标变换,以模拟物体的运动轨迹和行为。