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;
}