The Preliminary Contest for ICPC Asia Shanghai 2019 B. Light bulbs(卡了线段树空间的思维题)

本文探讨了一种涉及灯泡状态翻转的算法问题,通过两种不同的方法解决:线段树实现和优化的区间翻转策略。文章详细介绍了算法的实现过程,包括输入输出格式、核心代码和数据结构设计,旨在帮助读者理解和解决类似问题。

传送门:https://nanti.jisuanke.com/t/41399

题目描述

There are N N N light bulbs indexed from 0 0 0 to N − 1 N−1 N1. Initially, all of them are off.

A F L I P FLIP FLIP operation switches the state of a contiguous subset of bulbs. F L I P ( L , R ) FLIP(L, R) FLIP(L,R) means to flip all bulbs xx such that L ≤ x ≤ R L \leq x \leq R LxR. So for example, F L I P ( 3 , 5 ) FLIP(3, 5) FLIP(3,5) means to flip bulbs 3 , 4 and 5, and F L I P ( 5 , 5 ) FLIP(5,5) FLIP(5,5) means to flip bulb 5.

Given the value of N N N and a sequence of M M M flips, count the number of light bulbs that will be on at the end state.

输入格式

The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a line containing two integers N and M, the number of light bulbs and the number of operations, respectively. Then, there are M more lines, the ii-th of which contains the two integers L i L_i Liand R i R_i Ri, indicating that the ii-th operation would like to flip all the bulbs from L i L_i Li
to R i R_i Ri, inclusive.

1 ≤ T ≤ 1000 1 \leq T \leq 1000 1T1000

1 ≤ N ≤ 1 0 6 1 \leq N \leq 10^6 1N106

1 ≤ M ≤ 1000 1 \leq M \leq 1000 1M1000

0 ≤ L i ≤ R i ≤ N − 1 0 \leq L_i \leq R_i \leq N-1 0LiRiN1

输出格式

For each test case, output one line containing Case # x : y x: y x:y, where x is the test case number (starting from 1) and y is the number of light bulbs that will be on at the end state, as described above.

样例输入

2
10 2
2 6
4 8
6 3
1 1
2 3
3 4

样例输出

Case #1: 4
Case #2: 3



① 线段树做法(MLE)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int maxn = 1e6 + 10;
int t, n, m, x, y;
struct node { int l, r, sum, flip; } tree[maxn << 2];
 
inline const int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
    return x * f;
}
 
inline int ls(int id) { return id << 1; }
inline int rs(int id) { return id << 1 | 1; }
 
void push_up(int id)
{
    tree[id].sum = tree[ls(id)].sum + tree[rs(id)].sum;
}
 
void push_down(int id)
{
    if (tree[id].flip)
    {
        tree[ls(id)].flip ^= 1; tree[rs(id)].flip ^= 1;
        tree[ls(id)].sum = tree[ls(id)].r - tree[ls(id)].l + 1 - tree[ls(id)].sum;
        tree[rs(id)].sum = tree[rs(id)].r - tree[rs(id)].l + 1 - tree[rs(id)].sum;
        tree[id].flip = 0;
    }
}
 
void build(int id, int l, int r)
{
    tree[id].l = l; tree[id].r = r;
    tree[id].sum = tree[id].flip = 0;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(ls(id), l, mid);
    build(rs(id), mid + 1, r);
    push_up(id);
}
 
void update(int id, int l, int r)
{
    if (tree[id].l == l && tree[id].r == r)
    {
        tree[id].flip ^= 1;
        tree[id].sum = r - l + 1 - tree[id].sum;
        return;
    }
    push_down(id);
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (r <= mid) update(ls(id), l, r);
    else if (l > mid) update(rs(id), l, r);
    else
    {
        update(ls(id), l, mid);
        update(rs(id), mid + 1, r);
    }
    push_up(id);
}
 
int query(int id, int l, int r)
{
    if (tree[id].l == l && tree[id].r == r) return tree[id].sum;
    push_down(id);
    int mid = (tree[id].l + tree[id].r) >> 1;
    if (r <= mid) return query(ls(id), l, r);
    if (l > mid) return query(rs(id), l, r);
    return query(ls(id), l, mid) + query(rs(id), mid + 1, r);
}
 
int main()
{
    t = read();
    for (int i = 1; i <= t; i++)
    {
        printf("Case #%d: ", i);
        n = read(); m = read();
        build(1, 1, n);
        while (m--)
        {
            x = read() + 1; y = read() + 1;
            update(1, x, y);
        }
        printf("%d\n", query(1, 1, n));
    }
    return 0;
}

对于每一对Li、Ri,我们将其定义为:将Li之前的所有灯全都filp一次,再将Ri之前的所有灯全都filp一次,如图,即为将C段先翻转一次,再将A段翻转一次,这样一来,C段的灯被翻转了2次,即没有变化,而B段则被翻转了1次,达成了翻转[Li, Ri]区间的效果。
在这里插入图片描述
故,我们将所有的 Li(1 ~ Li-1)和 Ri+1(要包括Ri,故为Ri+1之前)保存在一个数组 v v v中,再将其由小到大排序遍历,维护在此坐标之前亮着的灯的数量 a n s ans ans(翻转一次即为 a n s = v [ i ] − a n s ans = v[i] - ans ans=v[i]ans

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int maxn = 1e6 + 10;
int v[maxn];
 
inline const int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
    return x * f;
}
 
int main()
{
    int t = read();
    for (int i = 1; i <= t; i++)
    {
        int n = read(), m = read(), cnt = 0, ans = 0;
        while (m--)
        {
            v[cnt++] = read();
            v[cnt++] = read() + 1;
        }
        sort(v, v + cnt);
        for (int j = 0; j < cnt; j++) ans = v[j] - ans;
        printf("Case #%d: %d\n", i, ans);
    }
    return 0;
}
【四轴飞行器】非线性三自由度四轴飞行器模拟器研究(Matlab代码实现)内容概要:本文围绕非线性三自由度四轴飞行器模拟器的研究展开,重点介绍基于Matlab代码实现的四轴飞行器动力学建模与仿真方法。研究构建了考虑非线性特性的飞行器数学模型,涵盖姿态动力学与运动学方程,实现了三自由度(滚转、俯仰、偏航)的精确模拟。文中详细阐述了系统建模过程、控制算法设计思路及仿真结果分析,帮助读者深入理解四轴飞行器的飞行动力学特性与控制机制;同时,该模拟器可用于算法验证、控制器设计与教学实验。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的高校学生、科研人员及无人机相关领域的工程技术人员,尤其适合从事飞行器建模、控制算法开发的研究生和初级研究人员。; 使用场景及目标:①用于四轴飞行器非线性动力学特性的学习与仿真验证;②作为控制器(如PID、LQR、MPC等)设计与测试的仿真平台;③支持无人机控制系统教学与科研项目开发,提升对姿态控制与系统仿真的理解。; 阅读建议:建议读者结合Matlab代码逐模块分析,重点关注动力学方程的推导与实现方式,动手运行并调试仿真程序,以加深对飞行器姿态控制过程的理解。同时可扩展为六自由度模型或加入外部干扰以增强仿真真实性。
基于分布式模型预测控制DMPC的多智能体点对点过渡轨迹生成研究(Matlab代码实现)内容概要:本文围绕“基于分布式模型预测控制(DMPC)的多智能体点对点过渡轨迹生成研究”展开,重点介绍如何利用DMPC方法实现多智能体系统在复杂环境下的协同轨迹规划与控制。文中结合Matlab代码实现,详细阐述了DMPC的基本原理、数学建模过程以及在多智能体系统中的具体应用,涵盖点对点转移、避障处理、状态约束与通信拓扑等关键技术环节。研究强调算法的分布式特性,提升系统的可扩展性与鲁棒性,适用于多无人机、无人车编队等场景。同时,文档列举了大量相关科研方向与代码资源,展示了DMPC在路径规划、协同控制、电力系统、信号处理等多领域的广泛应用。; 适合人群:具备一定自动化、控制理论或机器人学基础的研究生、科研人员及从事智能系统开发的工程技术人员;熟悉Matlab/Simulink仿真环境,对多智能体协同控制、优化算法有一定兴趣或研究需求的人员。; 使用场景及目标:①用于多智能体系统的轨迹生成与协同控制研究,如无人机集群、无人驾驶车队等;②作为DMPC算法学习与仿真实践的参考资料,帮助理解分布式优化与模型预测控制的结合机制;③支撑科研论文复现、毕业设计或项目开发中的算法验证与性能对比。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,重点关注DMPC的优化建模、约束处理与信息交互机制;按文档结构逐步学习,同时参考文中提及的路径规划、协同控制等相关案例,加深对分布式控制系统的整体理解。
<think>我们正在处理一个关于FDTD Solutions软件中文件无法打开的问。用户报告的错误是:"FDTD file pid_grating_coupler_preliminary_design.fsp not found or could not be opened"。这个错误通常意味着软件无法在指定路径找到该文件,或者文件存在但已损坏,或者没有足够的权限访问。 根据引用内容[^1],用户之前可能运行了一个Python脚本(pid_grating_coupler_sweep_2D.py),该脚本试图打开这个FSP文件。因此,问可能出现在脚本中指定的文件路径不正确,或者文件被移动、删除,或者权限问。 解决步骤: 1. **检查文件路径**: - 确保文件`pid_grating_coupler_preliminary_design.fsp`确实存在于脚本所期望的路径中。 - 在脚本中,检查打开文件时使用的路径是绝对路径还是相对路径。如果是相对路径,确保当前工作目录正确。 2. **检查文件权限**: - 确认用户有读取该文件的权限。在Windows上,可以右键点击文件,选择“属性”->“安全”选项查看权限。在Linux/macOS上,使用`ls -l`命令查看权限。 3. **检查文件是否损坏**: - 尝试手动打开该FSP文件(通过FDTD Solutions的图形界面)。如果图形界面也无法打开,则文件可能已损坏。 - 如果文件损坏,尝试从备份中恢复。 4. **检查脚本代码**: - 打开脚本`pid_grating_coupler_sweep_2D.py`,检查打开文件的部分。例如,在FDTD Solutions的脚本环境中,打开文件的命令可能是`load`或`open`。确保路径字符串正确,并且使用了正确的转义(在Windows中使用双反斜杠`\\`或正斜杠`/`)。 5. **其他可能性**: - 如果文件路径包含非英文字符,可能会引起问,尝试将路径改为全英文字符。 - 检查文件是否被其他程序占用(如另一个FDTD Solutions实例)。 如果用户是在运行脚本时遇到此错误,那么修改脚本中的文件路径可能是最直接的解决方法。如果文件丢失,则需要重新创建或从备份中恢复。 下面,我们将生成相关问,以帮助用户进一步排查或提供更多信息。</think>### FDTD文件无法打开的解决方案 当遇到"FDTD file pid_grating_coupler_preliminary_design.fsp not found or could not be opened"错误时,请按以下步骤排查: 1. **文件路径检查** - 确认文件是否存在于指定目录 - 检查路径中是否包含特殊字符或空格(建议使用纯英文路径) - 尝试使用绝对路径而非相对路径 - 验证脚本中的路径分隔符(Windows使用`\`或`/`,Linux/macOS使用`/`) 2. **文件权限验证** - 检查用户账户是否有文件读取权限 - 右键文件 > 属性 > 安全选项,确认当前用户有"读取"权限 - 尝试将文件复制到用户文档目录再打开 3. **文件完整性检查** - 确认文件大小是否正常(异常小的文件可能已损坏) - 尝试在其他FDTD Solutions实例中打开 - 检查备份版本是否能正常打开 4. **软件环境确认** - 确保FDTD Solutions版本与创建文件的版本兼容 - 检查Python脚本中加载文件的命令是否正确: ```python # 示例代码 - 检查脚本中的加载命令 import lumapi fdtd = lumapi.FDTD() fdtd.load("pid_grating_coupler_preliminary_design.fsp") # 确认路径正确 ``` - 重启FDTD Solutions软件和计算机 5. **脚本调试建议** - 在脚本开头添加路径打印: ```python import os print("当前工作目录:", os.getcwd()) print("文件路径:", os.path.abspath("pid_grating_coupler_preliminary_design.fsp")) ``` - 使用`try-except`捕获错误详情: ```python try: fdtd.load("pid_grating_coupler_preliminary_design.fsp") except Exception as e: print("加载失败:", str(e)) ``` 如果以上步骤仍无法解决,可能是文件损坏,建议从版本控制系统或备份中恢复文件[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值