CCF CSP认证2022年6月 归一化处理、寻宝!大冒险!、光线追踪

news2025/7/14 4:05:03

这是我第一次参加了这次CSP考试,300分,写了124三题,模拟题到现在都没看过题面没看,笑,t4写成模拟加数据结构,200+行,因为一个小错误调了1h,错失了大好机会。考试环境的VSC配置的字体太小,甚至连空格都看不清有还是没有,当时没想到可以重新配置,这可能也是我t4调了1h的原因。

距离下一次CSP考试考试还有20天左右,特此回顾。代码均为考试时提交的代码,补充思路。


T1 归一化处理

思路

数据归一化处理,根据给定公式进行计算。

在这里插入图片描述
在这里插入图片描述
这里要求了输出精度,通过流的格式标志值 i o s _ b a s e : : f i x e d ios\_base::fixed ios_base::fixed s e t p r e c i s i o n ( ) setprecision() setprecision()设置输出小数点后10位。

cout << fixed << setprecision(10) << (a[i] - av) / sD << '\n';

代码

void solve() {
    int n; cin >> n;

    vector<double> a(n);
    double sum = 0;
    for (int i = 0; i < n; i++) cin >> a[i], sum += a[i];
    double av = sum / n;

    double sD = 0;
    for (int i = 0; i < n; i++) {
        sD += (a[i] - av) * (a[i] - av);
    }
    sD /= n;
    sD = sqrt(sD);

    for (int i = 0; i < n; i++) {
        cout << fixed << setprecision(10) << (a[i] - av) / sD << '\n';
    }
}

T2 寻宝!大冒险!

思路

在这里插入图片描述
给定一个大矩阵 L L L和小矩阵 S S S,均为01矩阵,问 L L L有多少处和 S S S匹配( L L L有多少个子矩阵和 S S S相等)。
暴力匹配,时间为 O ( L 2 S 2 ) O(L^2S^2) O(L2S2),虽然一旦不匹配就可以终止,但乐观估计不优于 O ( L 2 ) O(L^2) O(L2).
因此,需要采取一些方法,注意到 n ≤ 1000 n\leq 1000 n1000,即‘1’的个数不超过1000,而且
在这里插入图片描述
因此从大矩阵‘1’的位置开始匹配,理论复杂度为 O ( n × S 2 ) O(n\times S^2) O(n×S2),约为 2.5 e 6 2.5e6 2.5e6,时间上可以过,但是还有空间的问题,无法开 1 e 18 1e18 1e18 b o o l bool bool数组,因此用 s e t < p a i r < i n t , i n t > > set<pair<int,int>> set<pair<int,int>>仅存储‘1’的坐标,匹配时要调用 f i n d ( ) find() find()方法找大矩阵中的对应位置,牺牲时间换空间,因此最终时间为 O ( n l o g n × S 2 ) O(nlogn\times S^2) O(nlogn×S2),约为 2.5 e 7 2.5e7 2.5e7.

代码

set<pair<int, int> > Set;
vector<pair<int, int> > a, b;

void solve() {
    int n, L, S;
    cin >> n >> L >> S;

    int x, y;
    for (int i = 1; i <= n; i++) {
        cin >> x >> y;
        Set.insert({x, y});
    }

    int m;
    for (int i = 0; i <= S; i++) {
        for (int j = 0; j <= S; j++) {
            cin >> m;
            if (m) {
                a.push_back({S - i, j});    // a tree
            }
            else b.push_back({S - i, j});
        }
    }
    int ans = 0;
    for (auto i : Set) {

        if (i.first + S > L || i.second + S > L) continue;
        bool ok = 1;
        // cout << "i: " << i.first << ' ' << i.second << '\n';
        for (auto j : a) {
            // cout << "j: " << j.first << ' ' << j.second << '\n';
            int tx = i.first + j.first;
            int ty = i.second + j.second;
            // cout << tx << ' ' << ty << '\n';
            if (Set.find({tx, ty}) == Set.end()) {
                ok = 0;
                break;
            }
        }

        for (auto j : b) {
            if (!ok) break;
            int tx = i.first + j.first;
            int ty = i.second + j.second;
            // cout << tx << ' ' << ty << '\n';
            if (Set.find({tx, ty}) != Set.end()) {
                ok = 0;
                break;
            }
        }
        if (ok) ans++;
    }

    cout << ans << '\n';
}

T4 光线追踪

思路

原来这题是图形学的背景,这学期刚刚在学CG,确实CG中很多用数据结构优化(比如多边形填充的APT)的算法。
在这里插入图片描述
限制了光线只能水平或者竖直地射,包括反射后的光线,而反射面的端点坐标均为整数,光源也设置在整点位置,因此可以认为光线在网格格线上运动,更进一步,可以认为反射面只设定在格点上。
在这里插入图片描述
光线在反射过程中存在耗散。
在这里插入图片描述
1,2定义了反射面的增删操作,3设置光源询问 t t t时间后,光线的位置 ( x , y ) (x,y) (x,y),以及剩余光线强度 I I I
在这里插入图片描述
这个 3 e 5 3e5 3e5的保证意味着可以 O ( n ) O(n) O(n)地将反射面的性质(耗散率,放置方向)存储(或者移除)到一定区间的格点中,用格点代表反射面,格点数就是 ∑ ∣ x 1 − x 2 ∣ \sum|x_1-x_2| x1x2.
在这里插入图片描述
网格大小为 1 e 9 2 1e9^2 1e92,因此必须不能 O ( t ) O(t) O(t)模拟光线的运动。光线的运动状态通过当前位置 ( x , y ) (x,y) (x,y)和方向 d d d,如果 d d d不变,可以 O ( 1 ) O(1) O(1)确定 t t t时间后的位置,而 d d d变化由反射引起,反射是由于经过了反射面,即具有反射性质的格点(下称为格点)。

  1. 如何快速找到该点? s e t set set上二分,将反射点存储于 s e t set set中,从当前点 ( x , y ) (x,y) (x,y)出发找第一个反射点。
  2. 通过 m a p < l l , s e t < l l > > map<ll, set<ll> > map<ll,set<ll>>嵌套STL存储,分别存储X,Y方向每条线上的反射点,其实一开始,我用了 s e t < i n t > s e t X [ 2 ∗ N ] set<int> setX[2 * N] set<int>setX[2N],提交后RE了,因为坐标可能为负数,而下标不能为负,然后第一次想到了这种用法,将数组下标范围扩大至负数域,而且是动态地开辟空间,不用为内存限制而烦恼!

结合代码讲讲:
定义了结构体 m i r r o r mirror mirror,解决题目规定的对反射面整体的增加和删除操作,对应结构体方法 i n i t init init c l r clr clr,而 r e s e t reset reset是将反射性质赋予区域中的格点,就是将该点存储于 m a p < l l , s e t < l l > > map<ll, set<ll> > map<ll,set<ll>> c l r clr clr中实现了移除,下面这句是进行空间的回收,动态性!其实这里可以将 i n i t init init r e s e t reset reset合在一起写。

if (setX[x].size() == 0) setX.erase(x);

w o r k work work函数模拟光线的运动,是递归函数,输入参数 x , y x,y x,y是当前坐标, d d d是方向, I I I是强度, t t t是询问 t t t时刻后的位置。

void work(ll x, ll y, int d, double I, ll t) {

这个函数我按照运动方向分为了4个部分写,因为每个方向上 s e t set set调用的二分方法不同, u p p e r _ b o u n d upper\_bound upper_bound或者 l o w e r _ b o u n d lower\_bound lower_bound,而且边界情况也不好统一表达,只能 i f e l s e ifelse ifelse分类讨论了。
具体看一种情况,光线沿着 x x x轴增加:
此时 y y y不变,首先判断该格线上是否有反射点,没有访问会RE:

if (setY.find(y) == setY.end()) {

若没有,则一直前进;否则,则调用 s e t set set自带的二分方法:

auto it = setY[y].upper_bound(x);   // 找到第一个大于x的数

若没有找到这样的反射点,则一直前进;否则可能发生发射,还要检查到达该点的用时,时间充足发生反射,写到这里大家肯定发现这是道具有大模拟性质的t4了。
发生反射,由于光线原来方向沿 x x x增加,只可能变为沿 y y y方向增加或者减少,这个通过镜子的放置方向确定,递归。

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int N = 1e5 + 5;
const int maxn = 1e5 + 5;

// set<int> setX[2 * N];
// set<int> setY[2 * N];

map<ll, set<ll> > setX;
map<ll, set<ll> > setY;
map<pair<ll, ll>, int> mp;

struct  mirror
{
    void init(int ID, ll a1, ll b1, ll a2, ll b2, double A) {
        id = ID;
        x1 = a1; y1 = b1; x2 = a2; y2 = b2; a = A;
    }
    void reset() {
        if (x1 > x2) dx = -1;
        else dx = 1;
        if (y1 > y2) dy = -1;
        else dy = 1;

        ll x = x1 + dx, y = y1 + dy;
        while (x != x2) {
            setX[x].insert(y);
            setY[y].insert(x);
            mp[{x, y}] = id;    // 将点对应至镜子
            x += dx; y += dy;
        }
    }
    void clr() {
        ll x = x1 + dx, y = y1 + dy;
        while (x != x2) {
            setX[x].erase(y);
            setY[y].erase(x);
            if (setX[x].size() == 0) setX.erase(x);
            if (setY[y].size() == 0) setY.erase(y);
            mp.erase({x, y});
            x += dx; y += dy;
        }
    }
    int id;
    ll x1, y1, x2, y2;
    int dx, dy;
    double a;
} M[maxn];

void work(ll x, ll y, int d, double I, ll t) {
    // cout << "work: " << x << ' ' << y << ' ' << d << ' ' << I << ' ' << t << '\n';
    
    if (I < 1.0) {  // 已经完全耗散
        cout << "0 0 0\n";
        return;
    }
    // if (x < 0 || y < 0) return;
    if  (d == 0) {  // x -> 沿着x轴增加
        if (setY.find(y) == setY.end()) {
            cout << x + t << ' ' << y << ' ' << (int)I << '\n';
            return;
        }
        auto it = setY[y].upper_bound(x);   // 找到第一个大于x的数
        if (it == setY[y].end()) {  // 若无则代表没有镜子
            cout << x + t << ' ' << y << ' ' << (int)I << '\n';
            return;
        }
        else {
            ll nx = *it;
            if (t < nx - x) {  // 看剩余时间是否充足
                cout << x + t << ' ' << y << ' ' << (int)I << '\n';
                return;
            }
            int mir = mp[{nx, y}];  // 进行一次反射
            auto Mir = M[mir];
            if (Mir.dx * Mir.dy > 0) {  // 判断镜子方向
                work(nx, y, 1, I * Mir.a, t - (nx - x));
            }
            else {
                work(nx, y, 3, I * Mir.a, t - (nx - x));
            }
        }
    }
    else if (d == 1) {  // y ^
        if (setX.find(x) == setX.end()) {
            cout << x << ' ' << y + t << ' ' << (int)I << '\n';
            return;
        }
        auto it = setX[x].upper_bound(y);
        if (it == setX[x].end()) {
            cout << x << ' ' << y + t << ' ' << (int)I << '\n';
            return;
        }
        else {
            ll ny = *it;
            if (t < ny - y) {
                cout << x << ' ' << y + t << ' ' << (int)I << '\n';
                return;
            }
            int mir = mp[{x, ny}];
            auto Mir = M[mir];
            if (Mir.dx * Mir.dy > 0) {
                work(x, ny, 0, I * Mir.a, t - (ny - y));
            }
            else {
                work(x, ny, 2, I * Mir.a, t - (ny - y));
            }
        }
    }
    else if (d == 2) {  // x <- 沿着x轴减少
        if (setY.find(y) == setY.end()) {
            cout << x - t << ' ' << y << ' ' << (int)I << '\n';
            return;
        }
        auto it = setY[y].lower_bound(x);
        if (it == setY[y].begin()) {    // 没有小于x的数
                cout << x - t << ' ' << y << ' ' << (int)I << '\n';
                return;
        }
        else {
            it--;   // 第一个小于x的数
            ll nx = *it;
            if (t < x - nx) {
                cout << x - t << ' ' << y << ' ' << (int)I << '\n';
                return;
            }
            int mir = mp[{nx, y}];
            auto Mir = M[mir];
            if (Mir.dx * Mir.dy > 0) {
                work(nx, y, 3, I * Mir.a, t - (x - nx));
            }
            else {
                work(nx, y, 1, I * Mir.a, t - (x - nx));
            }
        }
    }
    else if (d == 3) {  // y v
        if (setX.find(x) == setX.end()) {
            cout << x << ' ' << y - t << ' ' << (int)I << '\n';
            return;
        }
       auto it = setX[x].lower_bound(y);
        if (it == setX[x].begin()) {
                cout << x << ' ' << y - t << ' ' << (int)I << '\n';
                return;
        }
        else {
            it--; 
            ll ny = *it;
            if (t < y - ny) {
                cout << x << ' ' << y - t << ' ' << (int)I << '\n';
                return;
            }
            int mir = mp[{x, ny}];
            auto Mir = M[mir];
            if (Mir.dx * Mir.dy > 0) {
                work(x, ny, 2, I * Mir.a, t - (y - ny));
            }
            else {
                work(x, ny, 0, I * Mir.a, t - (y - ny));
            }
        }
    }
}

void solve() {
    int m; cin >> m;

    ll op, x1, y1, x2, y2, d, t, k;
    double a, I;
    for (int i = 1; i <= m; i++) {
        cin >> op;

        if (op == 1) {
            cin >> x1 >> y1 >> x2 >> y2 >> a;
            M[i].init(i, x1, y1, x2, y2, a);    // 添加反射镜
            M[i].reset();
        }
        else if (op == 2) {
            cin >> k;
            M[k].clr();
        }
        else if (op == 3) {
            cin >> x1 >> y1 >> d >> I >> t;
            if (t == 0) {
                cout << x1 << ' ' << y1 << ' ' << (int)I << '\n';
            }
            work(x1, y1, d, I, t);
        }
    }
}

int main() {
    // freopen("e.in", "r", stdin);
    // long double tt = 1.0;
    // cout << (int)tt << '\n';

    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    solve();
    // cout << "Hello!\n";

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38926.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[一篇读懂]C语言十讲:单链表的新建、查找

[一篇读懂]C语言十讲&#xff1a;单链表的新建、查找1. 与408关联解析及本节内容介绍1 与408关联解析2 本节内容介绍2. 头插法新建链表实战3. 尾插法新建链表实战4. 按位置查找及按值查找实战5. 往第i个位置插入元素实战6. 链表的调试方法总结234561. 与408关联解析及本节内容介…

面对无法投入模型训练的object类型数据在头疼,快来使用我的丝滑小连招

面对无法投入模型训练的object类型数据在头疼&#xff0c;快来使用我的丝滑小连招 前言 丝滑小连招 tip1- get_dummies完美one-hot&#xff08;str->int&#xff09; tip2 - rename_dims解决重名问题&#xff01; tip3 - insert且drop&#xff01;​​​​​​​ 前言 我…

小爱同学控制美的美居中的家电热水器,空调等

背景 家里大多数家电都是支持接入米家App的&#xff0c;美的家电不能接入小米&#xff0c;电脑安装Home Assistant成功实现小爱语音控制美的燃气热水器。 实现步骤&#xff1a; 1. 安装docker 我的电脑是windows的&#xff0c;那就直接安装docker desktop https://desktop.…

【Linux】基础指令(三) —— 收尾篇

文章目录前言zip 和 unzip 指令tar 指令bc 指令uname 指令history关机热键补充ctrl c↑ && ↓ctrl rctrl d指令拓展结语前言 今天为大家带来的是最后一部分基础指令讲解。主要内容为 7个指令讲解、热键补充、简单提一下指令的拓展 。内容相对之前较少&#xff0c;更…

服务器密码以及用户名怎么修改

服务器密码以及用户名怎么修改 我是艾西&#xff0c;今天给大家说下服务器密码如何修改 windows2003系统&#xff1a; 1、右键我的电脑&#xff0c;点击“管理”&#xff1a; 2、在“本地用户和组”中打开“用户”&#xff0c;在右侧找到 Administrator 账户进行修改。 200…

【linux】linux实操篇之任务调度

目录前言crond 任务调度概述基本语法快速入门案例案例一&#xff1a;每隔一分钟将ls -l /etc/ 追加到 /tmp/to.txt 文件案例二&#xff1a;每隔一分钟执行python文件结语前言 我们常用linux做一些定时任务&#xff0c;最常见的就是在服务器领域&#xff0c;我们常常做一些定时…

高分辨率格式理论

一个核心概念&#xff1a;人工粘性 考虑经典的双曲守恒律方程 ∂u∂t∂f∂x0{{\partial u} \over {\partial t}} {{\partial f} \over {\partial x}} 0∂t∂u​∂x∂f​0 可以写成守恒形式的数值格式 uin1uin−λ(f^i1/2n−f^i1/2n)u_i^{n 1} u_i^n - \lambda \left( {\ha…

基于ssm+mysql+jsp学生成绩管理系统(含实训报告)

基于ssmmysqljsp学生成绩管理系统(实训报告&#xff09;一、系统介绍二、功能展示1.学生信息查询2.学生信息添加3.学生信息修改4.学生信息删除四、获取源码一、系统介绍 系统主要功能&#xff1a;系统实现了学生信息查询、添加、修改、删除。 环境配置&#xff1a; Jdk1.8 M…

[附源码]java毕业设计智慧教学平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

储能辅助电力系统调峰的容量需求优化配置matlab/cplex

参考文献&#xff1a;储能辅助电力系统调峰的容量需求研究 摘要&#xff1a;建立了储能辅助电力系统调峰的容量需求优化配置模型&#xff0c;设置了含储能和不含储能两种仿真方案&#xff0c;将两个算例代入所提模型进行求解&#xff0c;得到最优的储能系统容量和功率配置&…

Flutter高仿微信-第52篇-群聊-清空聊天记录

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; //清空聊天记录对话框 void _cleanGroupChatDialog(){Lo…

【Python】数据类型 + 运算符 + 输入输出

文章目录一. 常量和表达式二. 变量和类型1. 什么是变量2. 变量的语法2.1 定义变量2.2 使用变量3. 变量的类型3.1 整数3.2 浮点数3.3 字符串3.4 布尔3.5 关于变量类型的几点补充三. 注释1. 什么是注释&#xff1f;2. 为什么要有注释&#xff1f;3. 如何写注释&#xff1f;3.1 注…

深度学习制作自己的数据集—为数据集打上标签保存为txt文件,并进行划分和加载数据集

目录 0 前言 1 为图片数据集打上标签并保存为txt文件 2 将txt文件中的图片标签数据集随机划分为训练集和测试集 3 加载txt文件中的图片标签数据集 0 前言 目前是被封控的第四天了&#xff0c;只能呆在宿舍不能出去&#xff0c;记得上次这样子还是一年前大四快毕业那时候了……

CyberController手机外挂番外篇:源代码的二次修改

文章目录前言调试过程中的疑问为什么一段时间不使用CyberController&#xff0c;翻译就无法触发了&#xff1f;为什么连接成功了&#xff0c;但却依然无法进行语音识别和翻译&#xff1f;多长时间TCP连接就会挂掉连接正常与断开连接有什么区别&#xff1f;不停进行翻译&#xf…

现代密码学导论-18-伪随机置换

目录 伪随机置换 PROPOSITION 3.26 伪随机置换和伪随机函数的关系 DEFINITION 3.27 强伪随机置换 伪随机置换 我们称F是含参数k的置换&#xff0c;当且仅当 且对于所有k&#xff0c; Fk是一对一的&#xff0c;即是满射的。 其中 lin 称为F的块长度 对于给定的 k、x和k、y&…

76.【图】

图( 一).图的基本结构(1).无序偶对.(2).有序偶对(3).有向图和无向图(4).权(5).网图(二).图的基本术语(1).邻接.依附(2).有向完全图,无向完全图(3).顶点的度,入度,出度(4).路径 路径长度 回路(5).简单路径 简单回路(6).子图(7).连通图 连通分量(8).强连通图 强连通分量(三).图的…

改进粒子滤波的无人机三维航迹预测方法(基于Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

骨传导耳机贴不紧咋办,推荐五款佩戴最稳固的骨传导蓝牙耳机

很多小伙伴都在反馈&#xff0c;骨传导耳机在佩戴时戴不稳&#xff0c;这关乎于耳机的材质有很大的关系&#xff0c;下面就给大家推荐几款佩戴十分牢固的骨传导耳机&#xff0c;不调人群使用哦~看看有没有自己喜欢的吧~ 1、南卡Runner Pro4骨传导蓝牙耳机 &#xffe5;1498 南…

图与图的深度优先遍历、广度优先遍历

文章目录&#x1f6a9;图的理解&#x1f341;无向图&#x1f341;有向图&#x1f341;完全图&#x1f341;常用性质&#x1f6a9;图的数据结构搭建&#x1f341;邻接矩阵&#x1f341;邻接表&#x1f341;邻接矩阵式存储的代码实现&#x1f341;邻接矩阵造图测试&#x1f341;邻…

从零开始打造一款基于SpringBoot+SpringCloud的后台权限管理系统

随着 Spring Boot 和 Spring Cloud 的诞生和流行&#xff0c;集智慧于大成的 Spring 技术体系成为行业开发的首选之一。市场代表需求&#xff0c;技术代表能力。显而易见&#xff0c;在当今开发领域中&#xff0c;谁能更好地掌握这些主流开发技术&#xff0c;谁就能在跟别人竞争…