参考题解:CCF CSP 202309-2 坐标变换(其二)_202309-2 坐标变换(其二)python-CSDN博客
博主在这篇文章中提到了时间复杂度,之前一直写代码没有注意到这个问题,但是自己确实就像博主说的那样尝试了暴力搜索,然后就是只拿到了80,确实m个测试,每个测试用到可能很多次循环,总体按最大来算就是n*m了,时间复杂度确实太高
所以在这里博主给我们提供了前缀和的思路,非常不错。
#include <stdio.h>
#include <math.h>
using namespace std;
int main()
{
int n, m;
scanf("%d %d", &n, &m);
double stretchPrefix[n + 1] = {1}, rotatePrefix[n + 1] = {0}; //拉伸操作的前缀积,旋转操作的前缀和
for (int ni = 0; ni < n; ++ni) {
int type;
double val;
scanf("%d %lf", &type, &val);
switch (type) {
case 1:
stretchPrefix[ni + 1] = val * stretchPrefix[ni];
rotatePrefix[ni + 1] = rotatePrefix[ni];
break;
case 2:
stretchPrefix[ni + 1] = stretchPrefix[ni];
rotatePrefix[ni + 1] = val + rotatePrefix[ni];
break;
default:
break;
}
}
for (int mi = 0; mi < m; ++mi) {
int i, j;
double x, y;
scanf("%d %d %lf %lf", &i, &j, &x, &y);
double k = stretchPrefix[j] / stretchPrefix[i - 1]; //求经过了i~j步的操作后的拉伸系数
double theta = rotatePrefix[j] - rotatePrefix[i - 1]; //求经过了i~j步操作后的旋转角度
double x1 = k * x;
double y1 = k * y;
double x2 = x1 * cos(theta) - y1 * sin(theta);
double y2 = x1 * sin(theta) + y1 * cos(theta);
printf("%lf %lf\n", x2, y2);
}
return 0;
}
从这个题目中学到的东西1.输出结果时要注意不需要放在一起输出
我们可以看到这个题目中测试了5个数据要输出5行,之前的我一直认为这五行必须一起输出,所以在我自己的代码中 还将输出结果给存了起来,从而达到最终再用一次循环来统一输出,但是事实上并不是这样的,实际上这个给出的样例输出是告诉我们最终输出的总体结果是这样的,并没有要求我们必须一起同时输出,忽然理解为什么有的一边输入一边输出最终也能ac了。这样确实就可以避免时间空间浪费。
2.接下来是前缀和的思想,前缀和要求我们将第一位置的元素来初始化好,并且在求几个数之和时也要注意下标相减的细节。
下面简单介绍了一下前缀和思想:
最后是附上我的代码,和题解中的大致一样
#include <stdio.h>
#include<math.h>
#include<iomanip>
#include<iostream>
using namespace std;
int main()
{
int n, m;
cin>>n>>m;
double stretchPrefix[n + 1]={1} , rotatePrefix[n + 1]={0};//first
for (int ni = 1; ni <= n; ni++) {
int type;
double val;
scanf("%d %lf", &type, &val);//second
switch (type) {
case 1:
stretchPrefix[ni] = val * stretchPrefix[ni-1];
rotatePrefix[ni] = rotatePrefix[ni-1];
break;
case 2:
stretchPrefix[ni] = stretchPrefix[ni-1];
rotatePrefix[ni] = val + rotatePrefix[ni-1];
break;
default:
break;
}
}
double k,theta,x1,y1,x2,y2,x,y;
int i,j;
for (int mi = 0; mi < m; mi++) {//这里设置变量可以学习一下,使用乱七八糟的字母会显得杂乱
scanf("%d %d %lf %lf", &i, &j, &x, &y);
k = stretchPrefix[j] / stretchPrefix[i - 1]; //求经过了i~j步的操作后的拉伸系数,还要注意这里使用的下标
theta = rotatePrefix[j] - rotatePrefix[i - 1]; //求经过了i~j步操作后的旋转角度
x1 = k * x;
y1 = k * y;
x2 = x1 * cos(theta) - y1 * sin(theta);
y2 = x1 * sin(theta) + y1 * cos(theta);
//这里设置x1,x2这些变量是因为如果直接用x进行操作之后由于y也要用到原来x的值,就会有问题
cout<<fixed<<setprecision(3)<<x2<<' '<<fixed<<setprecision(3)<<y2<<endl;
}
return 0;
}
说明代码中的两点,主要是针对于节省运行时间。
对于first:
数组初始化方式:在第一段代码中,stretchPrefix和rotatePrefix数组的初始化方式不要写成 stretchPrefix[0]=1.0; rotatePrefix[0]=0;,最好采用数组初始化列表的方式,可以提高数组初始化的效率。
对于second
输入输出方式:当对时间限制比较高时,可以不使用C++的输入输出流(cin/cout),而使用C语言的标准输入输出函数(scanf/printf)。一般来说,C语言的标准输入输出函数比C++的输入输出流执行速度更快。拿直观的数据来看,当然这个题目中的输入输出比较多
可以看到这个题目中我将cin换成了scanf,直接节省了1.1s,在输入输出比较多时,这很可观