第31次CCF计算机软件能力认证
1、 坐标变换(其一)
对于平面直角坐标系上的坐标 ( x , y ) (x,y) (x,y),小 P P P 定义了一个包含 n n n 个操作的序列 T = ( t 1 , t 2 , … , t n ) T = (t_1,t_2,…,t_n) T=(t1,t2,…,tn)。
其中每个操作 t i t_i ti( 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n)包含两个参数 d x i dx_i dxi 和 d y i dy_i dyi,表示将坐标 ( x , y ) (x,y) (x,y) 平移至 ( x + d x i , y + d y i ) (x+dx_i,y+dy_i) (x+dxi,y+dyi) 处。
现给定 m m m 个初始坐标,试计算对每个坐标 ( x j , y j ) (x_j,y_j) (xj,yj)( 1 ≤ j ≤ m 1 \le j \le m 1≤j≤m)依次进行 T T T 中 n n n 个操作后的最终坐标。
输入格式
输入共 n + m + 1 n+m+1 n+m+1 行。
输入的第一行包含空格分隔的两个正整数 n n n 和 m m m,分别表示操作和初始坐标个数。
接下来 n n n 行依次输入 n n n 个操作,其中第 i i i( 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n)行包含空格分隔的两个整数 d x i dx_i dxi、 d y i dy_i dyi。
接下来 m m m 行依次输入 m m m 个坐标,其中第 j j j( 1 ≤ j ≤ m 1 \le j \le m 1≤j≤m)行包含空格分隔的两个整数 x j x_j xj、 y j y_j yj。
输出格式
输出共 m m m 行,其中第 j j j( 1 ≤ j ≤ m 1 \le j \le m 1≤j≤m)行包含空格分隔的两个整数,表示初始坐标 ( x j , y j ) (x_j,y_j) (xj,yj) 经过 n n n 个操作后的位置。
数据范围
1
≤
n
,
m
≤
100
1 \le n,m \le 100
1≤n,m≤100,
所有输入数据(
x
,
y
,
d
x
,
d
y
x,y,dx,dy
x,y,dx,dy)均为整数且绝对值不超过
1
0
5
10^5
105。
输入样例:
3 2
10 10
0 0
10 -20
1 -1
0 0
输出样例:
21 -11
20 -10
样例说明
第一个坐标 ( 1 , − 1 ) (1,-1) (1,−1) 经过三次操作后变为 ( 21 , − 11 ) (21,-11) (21,−11);第二个坐标 ( 0 , 0 ) (0,0) (0,0) 经过三次操作后变为 ( 20 , − 10 ) (20,-10) (20,−10)。
思路: 直接存一个数组前n项和就可以了
2、坐标变换(其二)
对于平面直角坐标系上的坐标 ( x , y ) (x,y) (x,y),小 P P 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 \le \theta < 2\pi 0≤θ<2π)。易知旋转后的横坐标为 x cos θ − y sin θ x\cos\theta - y\sin\theta xcosθ−ysinθ,纵坐标为 x sin θ + y cos θ x\sin\theta + y\cos\theta xsinθ+ycosθ。
设定好了包含 n n n 个操作的序列 ( t 1 , t 2 , … , t n ) (t_1,t_2,…,t_n) (t1,t2,…,tn) 后,小 P P P 又定义了如下查询:
i j x y
:坐标 ( x , y ) (x,y) (x,y) 经过操作 t i , … , t j t_i,…,t_j ti,…,tj( 1 ≤ i ≤ j ≤ n 1 \le i \le j \le n 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
(表示拉伸
k
k
k 倍)或 2 θ
(表示旋转
θ
\theta
θ)。
接下来 m m m 行依次输入 m m m 个查询,每行包含空格分隔的四个整数 i i i、 j j j、 x x x 和 y y y,含义如前文所述。
输出格式
输出共 m m m 行,每行包含空格分隔的两个实数,表示对应查询的结果。
如果你输出的浮点数与参考结果相比,满足绝对误差不大于 0.1 0.1 0.1,则该测试点满分,否则不得分。
数据范围
1
≤
n
,
m
≤
1
0
5
1 \le n,m \le 10^5
1≤n,m≤105,
输入的坐标均为整数且绝对值不超过
1
0
6
10^6
106,
单个拉伸操作的系数
k
∈
[
0.5
,
2
]
k \in [0.5,2]
k∈[0.5,2],
任意操作区间
t
i
,
…
,
t
j
t_i,…,t_j
ti,…,tj(
1
≤
i
≤
j
≤
n
1 \le i \le j \le n
1≤i≤j≤n)内拉伸系数
k
k
k 的乘积在
[
0.001
,
1000
]
[0.001,1000]
[0.001,1000] 范围内。
输入样例:
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 \times 0.716 = 114151.88 159430×0.716=114151.88
纵坐标: − 511187 × 0.716 = − 366009.892 -511187 \times 0.716 = -366009.892 −511187×0.716=−366009.892
由于具体计算方式不同,程序输出结果可能与真实值有微小差异,样例输出仅保留了三位小数。
刚开始我还在那里傻傻地模拟,只能过60%,后来加了一个前缀和+二分查找,想着应该会多一点,结果还是60%,后来想着应该顺序好像没有关系,一次转60度,再转120度和一下子转180度不是一样的?直接两个前缀和就OK 了
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N = 1e5 + 5;
double multi[N];
double theta[N];
int main()
{
scanf("%d%d", &n, &m);
multi[0] = 1;
for (int i = 1; i <= n; i ++ )
{
double a , b;
scanf("%lf%lf", &a, &b);
double p = a == 1 ? b : 1;
multi[i] = multi[i-1] * p;
double q = a == 2 ? b : 0;
theta[i] = theta[i - 1] + q;
}
for (int i = 1; i <= m; i ++ )
{
int l,r;
double x,y;scanf("%d%d%lf%lf" , &l , &r, &x ,&y);
double a = multi[r] / multi[l-1];
double b = theta[r] - theta[l-1];
x*= a;
y*= a;
double x_ = x * cos(b) - y * sin(b);
double y_ = x * sin(b) + y * cos(b);
x = x_;
y = y_;
printf("%.3lf %.3lf\n" , x , y);
}
return 0;
}