CCF-CSP 202309-2 坐标变换(其二)

😸题目要求

对于平面直角坐标系上的坐标 ( x , y ) (x,y) (x,y),小 P 定义了如下两种操作:

  1. 拉伸 k k k 倍:横坐标 x x x 变为 k x kx kx,纵坐标 y y y 变为 k y ky ky
  2. 旋转 θ \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(1ijn) 后的新坐标。

对于给定的操作序列,试计算 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,m1000
全部的测试数据满足:

  • n , m ≤ 100000 n,m \leq 100000 n,m100000
  • 输入的坐标均为整数且绝对值不超过 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(1ijn) 内拉伸系数 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); 输出,也可以使用 cincout 输入输出浮点数;#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))

🐈场景拓展

本题是对上一道题的一个进阶和补充,主要目的在于坐标变换,它可以根据给定的操作类型和数值对坐标进行变换。主要应用场景包括但不限于:

  • 图形变换:可以通过修改操作类型和数值来实现平移、旋转、缩放等图形变换操作。
  • 数据分析与可视化:在数据分析和可视化领域,经常需要对数据进行坐标变换,以便更好地理解和展示数据。
  • 物体运动模拟:在物理模拟和游戏开发中,需要对物体进行坐标变换,以模拟物体的运动轨迹和行为。
  • 30
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值