CCF CSP——202206-5 PS无限版(70分题解)

问题描述

试题链接:PS无限版

70分题解

题目还是比较简单的,不至于长篇大论的(读题都累死人了),此题要求:有一系列的点(用数组保存下来),编号(1,2……,n),对编号[l,r]的点进行不同的7个操作:

第一个操作还是比较简单的,对编号在[l,r]中的点的坐标分别加a,b即可,即(x,y)——》(x+a,y+b)

在平面坐标系中,围绕一般的点旋转得到新的坐标是很困难的,而坐标系中有一个非常特殊的点,那就是原点,因此,根据第一个操作的提示,旋转中心平移到原点,即(x,y)——》(x-a,x-b),再进行旋转操作得到(x',y'),最后平移回去(x',y')——》(x'+a,y'+a)即可。

简单提一下关于原点旋转操作,因为题目给的角度,即弧度制,弧度制的两要素是点到原点构成的线段与x轴构成的角度和点到直线的距离,旋转后的点距离不变,角度增大θ,而平面坐标x,y分别可以用三角函数构造,即x = d \cos \alphay = d\sin \alpha,其中d为点到原点的距离,\alpha为点到原点线段与x轴夹角,最后求解就比较容易了,然后要将弧度制转换为正常坐标,转换方式同理,最后不要忘了平移回去。

 同上一题理论,将放缩中心平移到原点,需要操作的点相同位移,点用弧度制表示,此时,此操作变为d = d*\lambda(此时\lambda不用取绝对值),再换回正常坐标平移回去即可

 

 4、5操作有相同的求解方法,写在一起讨论。假设第5个操作为点位移到目的地点的操作,则第4个操作为第5个操作位移之后再位移相同距离,所以,第5个操作解决了,第4个操作就解决了,因此,直接分析第5个操作。

哈哈,没想到吧,这两个操作还是可以用平移+弧度来求解。这次平移直线到经过原点,将直线向下平移y_{0}个单位长度即可(y_{0}小于0表示向上),待操作点相同位移,然后利用三角函数性质即可得到目的点弧度表示(d*\cos \alpha -\theta\theta),最后转换,平移。

 6、7操作分别用一次变量然后输出即可,没什么难度。

题解代码

有一个非常苦逼的事是,我本来以为我的解法必然满分的,但是现实却给了残酷的一刀,用python实现以上解法,然后30分超时了,于是我改用了java和c++,70分超时,不得不佩服c++和java

分析与改进:虽然时间超限了,但空间还有很多,因此,满分题解可能是用空间换时间,留给大家讨论交流,我实在想不出怎么优化,或者还有其他更优秀的解法(欢迎大家分享)

python 30分

import math
n, q = map(int, input().split())
point_x = [0.0] * n
point_y = [0.0] * n
for i in range(n):
    x, y = map(float, input().split())
    point_x[i], point_y[i] = x, y
for _ in range(q):
    option = input().split()
    id = int(option[0])
    l, r = int(option[1]), int(option[2])
    if id == 1:
        a, b = float(option[3]), float(option[4])
        for index in range(l-1, r):
            x = point_x[index] + a
            y = point_y[index] + b
            point_x[index], point_y[index] = x, y
    elif id == 2:
        a, b, q = float(option[3]), float(option[4]), float(option[5])
        for index in range(l - 1, r):
            x, y = point_x[index] - a, point_y[index] - b
            d = math.sqrt(x ** 2 + y ** 2)
            ra = math.atan2(y, x) + q
            point_x[index], point_y[index] = d * math.cos(ra) + a, d * math.sin(ra) + b
    elif id == 3:
        a, b, q = float(option[3]), float(option[4]), float(option[5])
        for index in range(l-1, r):
            point_x[index], point_y[index] = (point_x[index] - a) * q + a, (point_y[index] - b) * q + b
    elif id == 4:
        a, b = float(option[3]), float(option[4])
        for index in range(l-1, r):
            x, y = point_x[index], point_y[index] - b
            d = math.sqrt(x**2 + y**2)
            ra = 2 * a - math.atan2(y, x)
            point_x[index], point_y[index] = d * math.cos(ra), d * math.sin(ra) + b
    elif id == 5:
        a, b = float(option[3]), float(option[4])
        for index in range(l - 1, r):
            x, y = point_x[index], point_y[index] - b
            ra = math.atan2(y, x) - a
            d = math.sqrt(x ** 2 + y ** 2) * math.cos(ra)
            point_x[index], point_y[index] = d * math.cos(a), d * math.sin(a) + b
    elif id == 6:
        print("%.6f" % (sum(point_x[l-1:r]) / (r - l + 1)), "%.6f" % (sum(point_y[l-1:r]) / (r - l + 1)))
    elif id == 7:
        a, b = float(option[3]), float(option[4])
        print("%.6f" % sum([(point_x[index] - a) ** 2 + (point_y[index] - b) ** 2 for index in range(l - 1, r)]))

c++ 70分

#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;

int main() {
    int n,p;
    cin >> n >> p;
    double points[n][2];
    for(int i = 0; i < n; i++){
        cin >> points[i][0] >> points[i][1];
    }
    double d,ra;
    int id,l,r;
    double a,b,s,x,y;

    while (p > 0){
        cin >> id >> l >> r;

        switch (id) {
            case 1:
                cin >> a >> b;
                for (int i = l - 1; i < r; i++) {
                    points[i][0] += a;
                    points[i][1] += b;
                }
                break;
            case 2:
                cin >> a >> b >> s;
                for (int i = l - 1; i < r; i++) {
                    x = points[i][0] - a;
                    y = points[i][1] - b;
                    d = sqrt(x * x + y * y);
                    ra = atan2(y, x) + s;
                    points[i][0] = d * cos(ra) + a;
                    points[i][1] = d * sin(ra) + b;
                }
                break;
            case 3:
                cin >> a >> b >> s;
                for (int i = l - 1; i < r; i++) {
                    points[i][0] = (points[i][0] - a) * s + a;
                    points[i][1] = (points[i][1] - b) * s + b;
                }
                break;
            case 4:
                cin >> s >> b;
                for (int i = l - 1; i < r; i++) {
                    x = points[i][0];
                    y = points[i][1] - b;
                    d = sqrt(x * x + y * y);
                    ra = 2 * s - atan2(y, x);
                    points[i][0] = d * cos(ra);
                    points[i][1] = d * sin(ra) + b;
                }
                break;
            case 5:
                cin >> s >> b;
                for (int i = l - 1; i < r; i++) {
                    x = points[i][0];
                    y = points[i][1] - b;
                    ra = atan2(y, x) - s;
                    d = sqrt(x * x + y * y) * cos(ra);

                    points[i][0] = d * cos(s);
                    points[i][1] = d * sin(s) + b;
                }
                break;
            case 6: {
                double totalX = 0;
                double totalY = 0;
                for (int i = l - 1; i < r; i++) {
                    totalX += points[i][0];
                    totalY += points[i][1];
                }
                cout << setiosflags(ios::fixed) << setprecision(6);
                cout << totalX / (r - l + 1) << " " << totalY / (r - l + 1) << endl;
            }
                break;
            case 7: {
                cin >> a >> b;
                double total = 0;
                for (int i = l - 1; i < r; i++) {
                    total += (points[i][0] - a) * (points[i][0] - a) + (points[i][1] - b) * (points[i][1] - b);
                }
                cout << setiosflags(ios::fixed) << setprecision(6);
                cout << total << endl;
            }
                break;
            default:
                break;
        }
        p--;
    }
    return 0;
}

java 70分

package leetcode;

import java.util.Scanner;

public class Solution {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int p = scan.nextInt();
        double[][] points = new double[n][2];
        for(int i = 0; i < n; i++){
            points[i][0] = scan.nextDouble();
            points[i][1] = scan.nextDouble();
        }

        int id,l,r;
        double a,b,s,x,y;
        double d,ra;
        while (p > 0){
            id = scan.nextInt();
            l = scan.nextInt();
            r = scan.nextInt();
            switch (id){
                case 1:
                    a = scan.nextDouble();
                    b = scan.nextDouble();
                    for (int i = l-1; i < r; i++){
                        points[i][0] += a;
                        points[i][1] += b;
                    }
                    break;
                case 2:
                    a = scan.nextDouble();
                    b = scan.nextDouble();
                    s = scan.nextDouble();
                    for (int i = l-1; i < r; i++) {
                        x = points[i][0] - a;
                        y = points[i][1] - b;
                        d = Math.sqrt(x*x+y*y);
                        ra = Math.atan2(y,x) + s;
                        points[i][0] = d * Math.cos(ra) + a;
                        points[i][1] = d * Math.sin(ra) + b;
                    }
                    break;
                case 3:
                    a = scan.nextDouble();
                    b = scan.nextDouble();
                    s = scan.nextDouble();
                    for (int i = l-1; i < r; i++) {
                        points[i][0] = (points[i][0] - a) * s + a;
                        points[i][1] = (points[i][1] - b) * s + b;
                    }
                    break;
                case 4:
                    s = scan.nextDouble();
                    b = scan.nextDouble();
                    for (int i = l-1; i < r; i++) {
                        x = points[i][0];
                        y = points[i][1] - b;
                        d = Math.sqrt(x*x+y*y);
                        ra = 2 * s - Math.atan2(y, x);
                        points[i][0] = d * Math.cos(ra);
                        points[i][1] = d * Math.sin(ra) + b;
                    }
                    break;
                case 5:
                    s = scan.nextDouble();
                    b = scan.nextDouble();
                    for (int i = l-1; i < r; i++) {
                        x = points[i][0];
                        y = points[i][1] - b;
                        ra = Math.atan2(y, x) - s;
                        d = Math.sqrt(x*x+y*y) * Math.cos(ra);

                        points[i][0] = d * Math.cos(s);
                        points[i][1] = d * Math.sin(s) + b;
                    }
                    break;
                case 6:
                    double totalX=0;
                    double totalY=0;
                    for (int i = l-1; i < r; i++) {
                        totalX += points[i][0];
                        totalY += points[i][1];
                    }
                    System.out.printf("%.6f %.6f\n",totalX/(r-l+1),totalY/(r-l+1));
                    break;
                case 7:
                    double total = 0;
                    a = scan.nextDouble();
                    b = scan.nextDouble();
                    for (int i = l-1; i < r; i++) {
                        total += (points[i][0] - a) * (points[i][0] - a) + (points[i][1] - b) * (points[i][1] - b);
                    }
                    System.out.printf("%.6f\n", total);
                    break;
            }
            p--;
        }
    }
}

写在最后

因为这道题,让我意识到,同样的解法,不同的语言会可能会得到不一样的分数,所以有些题没拿到满分可以考虑换一种语言。

最后,求打赏

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值