题目
问题描述
样例输入
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 倍。
横坐标:159430×0.716=114151.88
纵坐标:−511187×0.716=−366009.892
由于具体计算方式不同,程序输出结果可能与真实值有微小差异,样例输出仅保留了三位小数。
评测用例规模与约定
80% 的测试数据满足:m,n≤1000;
全部的测试数据满足:
-
m,n≤100000;
-
输入的坐标均为整数且绝对值不超过 1000000;
-
单个拉伸操作的系数 k∈[0.5,2];
-
任意操作区间 ti,⋯,tj(1≤i≤j≤n)内拉伸系数 k 的乘积在 [0.001,1000] 范围内。
评分方式
如果你输出的浮点数与参考结果相比,满足绝对误差不大于 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()
调用三角函数。
解答1(直接模拟)
由于80% 的测试数据满足:m,n≤1000,直接模拟即可,得分80分
时间复杂度O(m*n)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] type = new int[n + 1]; // 记录操作的类型
double[] delta = new double[n + 1]; //记录变化量
for (int i = 1; i <= n; i++) {
type[i] = sc.nextInt();
delta[i] = sc.nextDouble();
}
for (int i = 0; i < m; ++i) {
int start = sc.nextInt();
int end = sc.nextInt();
double x = sc.nextDouble();
double y = sc.nextDouble();
for (int j = start; j <= end; ++j) {
if (type[j] == 1) { //拉伸操作
x *= delta[j];
y *= delta[j];
} else { //旋转操作
double sin = Math.sin(delta[j]), cos = Math.cos(delta[j]);
double tmp = x * cos - y * sin;
y = x * sin + y * cos;
x = tmp;
}
}
System.out.println(x + " " + y);
}
}
}
解答2(极坐标+前缀和)
注意到一个操作是改变与原点的距离,一个操作是改变与x轴所夹成的角度,如果考虑坐标在极坐标系下的表示形式,会发现这两种操作只是分别对其中一维进行操作,且这些操作是可逆的,且不会相互影响。因此我们就预处理出前缀和数组。然后对于一个点问经过操作start到end的结果,先对它施加start到end操作的影响,再消除1到start - 1操作的影响,即可得到start到end操作的结果。
施加影响,就是长度*k,角度 +θ,消除影响,就是长度 / k,角度 −θ。
最后根据r和 θ 还原出x=rcosθ,y=rsinθ。
时间复杂度为 O(n+m).
import java.util.Scanner;
/*
* 极坐标+前缀和 O(m + n) 100分
* */
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
double[] side = new double[n + 1]; //坐标伸缩量的前缀和
double[] rad = new double[n + 1]; //弧度变化量的前缀和
side[0] = 1.0;
//预处理前缀和数组
for (int i = 1; i < n + 1; i++) {
int type = sc.nextInt();
double delta = sc.nextDouble();
if (type == 1) {
side[i] = delta * side[i - 1];
rad[i] = rad[i - 1];
} else {
rad[i] = delta + rad[i - 1];
side[i] = side[i - 1];
}
}
for (int i = 0; i < m; i++) {
int start = sc.nextInt();
int end = sc.nextInt();
double x = sc.nextDouble();
double y = sc.nextDouble();
//起始点的极坐标r,Θ
double r = Math.sqrt(x * x + y * y);
double theta = Math.atan2(y, x);
//执行start到end的一系列操作
r *= side[end] / side[start - 1];
theta += rad[end] - rad[start - 1];
//最后得出该点的平面直角坐标
x = r * Math.cos(theta);
y = r * Math.sin(theta);
System.out.println(x + " " + y);
}
}
}