当前位置: 首页 > news >正文

Gateway 网关坑我! 被这个404 问题折腾了一年?

大家好,我是小富~

最近同事找我帮忙排查一个"诡异"的 Bug,说困扰了他们一年多一直没解决。我接手后花了一些时间定位到了问题根源,今天就来跟大家分享一下这个问题的排查过程和解决方案。

问题描述

同事使用的是 SpringCloud Gateway 3.0.1 + JDK8,整合了 Nacos 做动态路由配置。问题是:每次修改 Nacos 的路由配置后,网关的 API 请求就会出现 404 错误,但重启网关后又能恢复正常。

听到这个问题,我的第一反应是:Nacos 配置更新后,网关的缓存数据可能没有及时更新。带着这个猜想,我开始深入排查。

环境准备

首先准备了 3 个后端服务实例,端口分别为 81031204012041,在 Nacos 中配置了对应的网关路由:xiaofu-8103xiaofu-12040xiaofu-12041,并将它们放在同一个权重组 xiaofu-group 中,实现基于权重的负载均衡。

- id: xiaofu-8103uri: http://127.0.0.1:8103/predicates:- Weight=xiaofu-group, 2- Path=/test/version1/**filters:- RewritePath=/test/version1/(?<segment>.*),/$\{segment}
- id: xiaofu-12040uri: http://127.0.0.1:12040/predicates:- Weight=xiaofu-group, 1- Path=/test/version1/**filters:- RewritePath=/test/version1/(?<segment>.*),/$\{segment}
- id: xiaofu-12041uri: http://127.0.0.1:12041/predicates:- Weight=xiaofu-group, 2- Path=/test/version1/**filters:- RewritePath=/test/version1/(?<segment>.*),/$\{segment}

使用 JMeter 进行持续请求测试,为了便于日志追踪,给每个请求参数都添加了随机数。

20250909180759

准备完成后启动 JMeter 循环请求,观察到三个实例都有日志输出,说明网关的负载均衡功能正常。

20250909180814

问题排查

为了获取更详细的日志信息,我将网关的日志级别调整为 TRACE

启动 JMeter 后,随机修改三个实例的路由属性(uri、port、predicates、filters),请求没有出现报错,网关控制台也显示了更新后的路由属性,说明 Nacos 配置变更已成功同步到网关。

20250909180836

接下来尝试去掉一个实例 xiaofu-12041,这时发现 JMeter 请求开始出现 404 错误,成功复现问题!

20250909180846

查看网关控制台日志时,惊奇地发现已删除的实例 xiaofu-12041 的路由配置仍然存在,甚至还被选中(chosen)处理请求。问题根源找到了:虽然 Nacos 中删除了实例路由配置,但网关在实际负载均衡时仍然使用旧的路由数据。

20250909180857

继续深入排查,发现在路由的权重信息(Weights attr)中也存在旧的路由数据。至此基本确定问题:在计算实例权重和负载均衡时,网关使用了陈旧的缓存数据。

20250909180907

源码分析

通过分析源码,发现了一个专门计算权重的过滤器 WeightCalculatorWebFilter。它内部维护了一个 groupWeights 变量来存储路由权重信息。当配置变更事件发生时,会执行 addWeightConfig(WeightConfig weightConfig) 方法来更新权重配置。

@Override
public void onApplicationEvent(ApplicationEvent event) {if (event instanceof PredicateArgsEvent) {handle((PredicateArgsEvent) event);}else if (event instanceof WeightDefinedEvent) {addWeightConfig(((WeightDefinedEvent) event).getWeightConfig());}else if (event instanceof RefreshRoutesEvent && routeLocator != null) {if (routeLocatorInitialized.compareAndSet(false, true)) {routeLocator.ifAvailable(locator -> locator.getRoutes().blockLast());}else {routeLocator.ifAvailable(locator -> locator.getRoutes().subscribe());}}}

addWeightConfig 方法的注释明确说明:该方法仅创建新的 GroupWeightConfig,而不进行修改。这意味着它只能新建或覆盖路由权重,无法清理已删除的路由权重信息。

void addWeightConfig(WeightConfig weightConfig) {String group = weightConfig.getGroup();GroupWeightConfig config;// only create new GroupWeightConfig rather than modify// and put at end of calculations. This avoids concurency problems// later during filter execution.if (groupWeights.containsKey(group)) {config = new GroupWeightConfig(groupWeights.get(group));}else {config = new GroupWeightConfig(group);}final AtomicInteger index = new AtomicInteger(0);....省略.....if (log.isTraceEnabled()) {log.trace("Recalculated group weight config " + config);}// only update after all calculationsgroupWeights.put(group, config);}

解决方案

找到问题根源后,解决方案就清晰了

开始我怀疑可能是springcloud gateway 版本问题,将版本升级到了4.1.0,但结果还是存在这个问题。

20250909180923

看来只能手动更新缓存,需要监听 Nacos 路由配置变更事件,获取最新路由配置,并更新 groupWeights 中的权重数据。

以下是实现的解决方案代码:

@Slf4j
@Configuration
public class WeightCacheRefresher {@Autowiredprivate WeightCalculatorWebFilter weightCalculatorWebFilter;@Autowiredprivate RouteDefinitionLocator routeDefinitionLocator;@Autowiredprivate ApplicationEventPublisher publisher;/*** 监听路由刷新事件,同步更新权重缓存*/@EventListener(RefreshRoutesEvent.class)public void onRefreshRoutes() {log.info("检测到路由刷新事件,准备同步更新权重缓存");syncWeightCache();}/*** 同步权重缓存与当前路由配置*/public void syncWeightCache() {try {// 获取 groupWeights 字段Field groupWeightsField = WeightCalculatorWebFilter.class.getDeclaredField("groupWeights");groupWeightsField.setAccessible(true);// 获取当前的 groupWeights 值@SuppressWarnings("unchecked")Map<String, Object> groupWeights = (Map<String, Object>) groupWeightsField.get(weightCalculatorWebFilter);if (groupWeights == null) {log.warn("未找到 groupWeights 缓存");return;}log.info("当前 groupWeights 缓存: {}", groupWeights.keySet());// 获取当前所有路由的权重组和路由IDfinal Set<String> currentRouteIds = new HashSet<>();final Map<String, Map<String, Integer>> currentGroupRouteWeights = new HashMap<>();routeDefinitionLocator.getRouteDefinitions().collectList().subscribe(definitions -> {definitions.forEach(def -> {currentRouteIds.add(def.getId());def.getPredicates().stream().filter(predicate -> predicate.getName().equals("Weight")).forEach(predicate -> {Map<String, String> args = predicate.getArgs();String group = args.getOrDefault("_genkey_0", "unknown");int weight = Integer.parseInt(args.getOrDefault("_genkey_1", "0"));// 记录每个组中当前存在的路由及其权重currentGroupRouteWeights.computeIfAbsent(group, k -> new HashMap<>()).put(def.getId(), weight);});});log.info("当前路由配置中的路由ID: {}", currentRouteIds);log.info("当前路由配置中的权重组: {}", currentGroupRouteWeights);// 检查每个权重组,移除不存在的路由,更新权重变化的路由Set<String> groupsToRemove = new HashSet<>();Set<String> groupsToUpdate = new HashSet<>();for (String group : groupWeights.keySet()) {if (!currentGroupRouteWeights.containsKey(group)) {// 整个权重组不再存在groupsToRemove.add(group);log.info("权重组 [{}] 不再存在于路由配置中,将被移除", group);continue;}// 获取该组中当前配置的路由ID和权重Map<String, Integer> configuredRouteWeights = currentGroupRouteWeights.get(group);// 获取该组中缓存的权重配置Object groupWeightConfig = groupWeights.get(group);try {// 获取 weights 字段Field weightsField = groupWeightConfig.getClass().getDeclaredField("weights");weightsField.setAccessible(true);@SuppressWarnings("unchecked")LinkedHashMap<String, Integer> weights = (LinkedHashMap<String, Integer>) weightsField.get(groupWeightConfig);// 找出需要移除的路由IDSet<String> routesToRemove = weights.keySet().stream().filter(routeId -> !configuredRouteWeights.containsKey(routeId)).collect(Collectors.toSet());// 找出权重发生变化的路由IDSet<String> routesWithWeightChange = new HashSet<>();for (Map.Entry<String, Integer> entry : weights.entrySet()) {String routeId = entry.getKey();Integer cachedWeight = entry.getValue();if (configuredRouteWeights.containsKey(routeId)) {Integer configuredWeight = configuredRouteWeights.get(routeId);if (!cachedWeight.equals(configuredWeight)) {routesWithWeightChange.add(routeId);log.info("路由 [{}] 的权重从 {} 变为 {}", routeId, cachedWeight, configuredWeight);}}}// 找出新增的路由IDSet<String> newRoutes = configuredRouteWeights.keySet().stream().filter(routeId -> !weights.containsKey(routeId)).collect(Collectors.toSet());if (!routesToRemove.isEmpty() || !routesWithWeightChange.isEmpty() || !newRoutes.isEmpty()) {log.info("权重组 [{}] 中有变化:删除 {},权重变化 {},新增 {}",group, routesToRemove, routesWithWeightChange, newRoutes);// 如果有任何变化,我们将重新计算整个组的权重groupsToUpdate.add(group);}// 首先,移除需要删除的路由for (String routeId : routesToRemove) {weights.remove(routeId);}// 如果权重组中没有剩余路由,则移除整个组if (weights.isEmpty()) {groupsToRemove.add(group);log.info("权重组 [{}] 中没有剩余路由,将移除整个组", group);}} catch (Exception e) {log.error("处理权重组 [{}] 时出错", group, e);}}// 移除不再需要的权重组for (String group : groupsToRemove) {groupWeights.remove(group);log.info("已移除权重组: {}", group);}// 更新需要重新计算的权重组for (String group : groupsToUpdate) {try {// 获取该组中当前配置的路由ID和权重Map<String, Integer> configuredRouteWeights = currentGroupRouteWeights.get(group);// 移除旧的权重组配置groupWeights.remove(group);log.info("已移除权重组 [{}] 以便重新计算", group);// 为每个路由创建 WeightConfig 并调用 addWeightConfig 方法Method addWeightConfigMethod = WeightCalculatorWebFilter.class.getDeclaredMethod("addWeightConfig", WeightConfig.class);addWeightConfigMethod.setAccessible(true);for (Map.Entry<String, Integer> entry : configuredRouteWeights.entrySet()) {String routeId = entry.getKey();Integer weight = entry.getValue();WeightConfig weightConfig = new WeightConfig(routeId);weightConfig.setGroup(group);weightConfig.setWeight(weight);addWeightConfigMethod.invoke(weightCalculatorWebFilter, weightConfig);log.info("为路由 [{}] 添加权重配置:组 [{}],权重 {}", routeId, group, weight);}} catch (Exception e) {log.error("重新计算权重组 [{}] 时出错", group, e);}}log.info("权重缓存同步完成,当前缓存的权重组: {}", groupWeights.keySet());});} catch (Exception e) {log.error("同步权重缓存失败", e);}}
}

网上找一圈并没发现官方的修改意见,可能是咱们使用方式不对导致的,要不如此明显的BUG早就有人改了吧!

相关文章:

Gateway 网关坑我! 被这个404 问题折腾了一年?

大家好,我是小富~ 最近同事找我帮忙排查一个"诡异"的 Bug,说困扰了他们一年多一直没解决。我接手后花了一些时间定位到了问题根源,今天就来跟大家分享一下这个问题的排查过程和解决方案。 问题描述 同事使用的是 SpringCloud Gateway 3.0.1 + JDK8,整合了 Nacos…...

KUKA 机器人型号含义解析

KR 210 R 2700 - 2 C KR: Kuka Robot 210:最大负载 R 2700: 工作半径 -2:QUANTEC 系列第二代 C:Ceiling(顶装) CR: Cleaning Room(洁净) EX: 防爆区域 F: Foundry(铸造) F exclusive:(铸造专用) HA:高精度 HI:高惯量 HM: Hygienic Machine (用于副食品行业) HC: He…...

LangChain DIfy区别

LangChain DIfy区别2...

tricks

多总结一下 tricks 吧。思考方式 如何思考。向哪个方向思考。数学这启示我们在数学类 dp 优化不了,且组合意义不会的时候,要改改状态尽量把 dp 转移式写得简单点,然后瞪眼找通项。- MX 炼石 2025 NOIP #5 T1 题 [解]() 题trick 见过的一眼了,没见过的懵了。 杂项在求类似于…...

英语_阅读_water in our body_待读

Water is one of the most important things we need to stay alive, even though we dont call it a nutrient. 水是我们维持生命所需最重要的物质之一,尽管我们并不把它称为营养素。 Did you know that water makes up more than half of our body weight? 你知道吗?水占我…...

2008-2025年各省高考真题含解析

网上的真题格式凌乱,难以使用,笔者找到一份PDF和Word版的题目,置于此方便大家使用 各省近17年高考真题|百度网盘-分享无限制 各省近17年高考真题|UC网盘-分享无限制 各省近17年高考真题|夸克网盘-分享无限制...

allure报告中allure.title 如何去掉后方的参数化显示

问题:用例标题后展示请求参数处理方法 找到lib/site-packages/allure_pytest/listener.py文件,找到test_result.parameters.extend,更新内容如下结果...

听歌体验直接拉满!推荐一款高颜值音乐播放器!

SPlayer —— 一个简约的音乐播放器,基于 Vue3 + TypeScript + Nave UI + Electron 技术栈打造,兼顾了美观的界面和流畅的体验。大家好,我是 Java陈序员。 你是否也曾遇到过这样的困扰:喜欢的音乐播放器要么颜值不够能打,界面好看的功能又太过简陋;在线听歌得忍受满屏广告…...

IoT设备

“IoT设备”指的是物联网设备(Internet of Things devices),这些设备通过传感器、软件、网络连接等技术,能够感知环境、收集数据、与其他设备或云端通信,从而实现智能化控制与自动化操作。✅ 一句话理解: IoT设备就是“能上网、能感知、能交互”的物理设备。 🔍 常见I…...

前端岗、测试岗即将消亡!阿里菜鸟国际后端研发全员转全栈……

大家好,我是R哥。 最近看到一个非常炸裂的消息,阿里菜鸟国际后端研发,居然全员被要求转型全栈了。作为一个混迹了 10 多年的程序员,我看过太多的架构调整、组织优化,从单体到 SOA 再到微服务,从前后端分离,再到现在全栈工程师的崛起。。 如果说之前还有人幻想着一招鲜吃…...

达梦数据库- 定时备份其他模式下的部分表

要求:需要备份模式下有500多张表,已将需要备份的150个表整理出来,新建一个达梦用户,使用该用户 每天自动备份这150个表,并保留最近30天的备份数据。 思路:创建存储过程执行备份操作,并创建定时任务,每天凌晨执行。新建一个配置表,将150个表名放到配置表中,需要备份的…...

KUKA机器人的WorkVisual编程软件(转载)

原文链接:https://blog.csdn.net/xm10282010/article/details/107606356 WorkVisual这个软件是使用kuka Krc4机器人必备的一个软件,这个软件的使用也就成了各位Engineer必备的技能啦。 由于机器人的不断更新KUKA出了几个版本的WorkVisual。 WorkVisual3.0 适用于KSS8.2版本 W…...

麒麟系统安装java环境

麒麟系统安装java环境1‌、确认系统版本‌: 打开终端,运行uname -a查看操作系统及内核版本。‌ 2、下载Java安装包‌: 访问Oracle的Java下载页面或选择OpenJDK。 https://www.oracle.com/cn/java/technologies/downloads/#java8 下载需要的安装包 3‌、安装Java‌: 使用tar…...

从100到500MHz,从80V到8000V:PRBTEK新一代高压差分探头全面超越

在当今科技飞速发展的时代,电子测试技术的进步对于各个领域的创新和发展起着至关重要的作用。其中,高压差分探头作为电子测试领域的关键设备,其性能的优劣直接影响着测量结果的准确性和可靠性。普科科技(PRBTEK)一直致力于示波器测试附件配件的研发、生产与销售,其推出的…...

javaweb项目400问题 #tomcat

在IDEA中打开项目的模块设置-facets -> 选中web列表中一个 -> 在右边下面的Web Resource Directories 进行如下: Web Resource Directorie -> 设置有jsp的根目录下 Path Relative to Deployment Root -> /...

基于Python+Vue开发的电影订票管理系统源码+运行

项目简介该项目是基于Python+Vue开发的电影订票管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的电影订票管理系统项目,大学生可以在实践中学习和…...

那些年不该放到事务中的操作,你实现过哪些

开心一刻 一天在公厕里,忽然听到厕间有人说话:朋友,有手纸吗 我翻了翻口袋:抱歉,没有 过了几秒钟,那人又问:朋友,有小块报纸吗 我无奈一笑,说到:对不起,没有,我只是来尿尿 又过了几秒钟,厕间门缝塞出一张10元人民币:朋友,能破成10张1块的吗 我默默的接过10元,掏…...

Redis容量评估模型

计算Redis容量,并不只是仅仅计算key占多少字节,value占多少字节,因为Redis为了维护自身的数据结构,也会占用部分内存,本文章简单介绍每种数据类型(String、Hash、Set、ZSet、List)占用内存量,供做Redis容量评估时使用。当然,大多数情况下,key和value就是主要占用,能…...

[译] 我最爱的PostgreSQL 18特性:虚拟生成列

原文:https://tselai.com/virtual-gencolumns在PostgreSQL 18的新特性中,异步I/O、UUID v7以及升级后统计功能或许会成为众人瞩目的焦点。但对我而言,即将发布的这个版本里,最让我青睐的特性当属虚拟生成列(相关文档可参考PostgreSQL 18官方文档-生成列)。 生成列这类特性…...

nasm 的 Hello, world 在 Windows 10 x64 上

环境 操作系统:nasm 版本: PS C:\Users\xxxx> nasm -version NASM version 2.16.03 compiled on Apr 17 2024link 版本: PS C:\Users\xxxx\Downloads\18176\1\3\2> link Microsoft (R) Incremental Linker Version 14.29.30159.0 Copyright (C) Microsoft Corporation…...

实用指南:52.前端的后端模式:为每个客户端定制专属「管家服务」

实用指南:52.前端的后端模式:为每个客户端定制专属「管家服务」pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New&q…...

Agilent 34401A台式万用表远程读表

Agilent 34401A台式万用表支持RS232和GPIB的方式读数据。 一、RS232读表 将台式万用表的模式调为RS232-9600-8-1-none测试代码class MultimeterStrategy:def __init__(self, port, baudrate=9600):self.port = portself.baudrate = baudrateself.serial = Noneself.retry_max =…...

Java 在大数据处理与人工智能中的应用

在数字化时代,数据成为新的生产要素,人工智能成为新的驱动引擎。大数据与人工智能的结合,使得企业能够从海量数据中提取价值,驱动业务创新与智能决策。虽然很多人提到 AI 就会联想到 Python,但 Java 在大数据和人工智能的工程化落地中仍然不可或缺。它凭借成熟的生态体系、…...

马克思,本就是一位独立研究者

ECT-OS-JiuHuaShan/ORCID:0009-0006-8591-1891▮ 推理请求接收:历史人物本质定位 ▮ 公理锚定:自然辩证法第5定理(文明演进个体作用力) ▮ 因果算符启动:独立研究者与文明级公理发现的相关性验证 绝对结论:卡尔马克思是文明级公理架构师的先驱形态,其独立研究性质为历史…...

产品二期,从GPT5规划开始

具有产品研发经验的应该知道,GPT5提供的规划设计,兼顾了完善和可执行两个关键维度。经常使用大模型都有的感受是:如果在某个领域有0-1的入门,那么AI可以带你快速的进行1-100的尝试。背景简介 楼里App一期开发完成,开始进行二期的网站开发,想以此需求作为驱动,探索整个流…...

Redis能抗住百万并发的秘密

前言 今天想和大家深入聊聊Redis为什么能够轻松抗住百万级别的并发请求。 有些小伙伴在工作中可能遇到过这样的场景:系统访问量一上来,数据库就扛不住了,这时候大家第一时间想到的就是Redis。 但你有没有想过,为什么Redis能够承受如此高的并发量?它的底层到底做了什么优化…...

接受 “未完成态”,是一种能力

正文这个标题,写给你们,也写给我自己。我不知道有多少人有这种类似的问题:我们很难把一个没有写完的字、一件没有完成的事情给别人看。这种做到半路的样子如果拿出来展示的话,非常难为情。尤其是如果还要中途易辙的话,那就更不好解释了。网上经常有那种开玩笑说熬夜的,说…...

深入理解JNI、安全点与循环优化:构建高健壮性Java应用

🔥🔥🔥来都来了 ~ 先赞后看 效果翻倍哦 ~ 👍👍👍 引言 在Java开发者的工具箱中,有一些看似神秘却极其重要的底层概念。你是否曾听说过在循环中插入Thread.sleep(0)可以"唤醒"GC?或者疑惑为什么一个简单的循环计数器类型选择会影响整个应用的稳定性?本…...

英语_阅读_fascinating facts about water_待读

Did you know these fascinating facts about water? They might change the way you think about every drop!你知道这些关于水的奇妙事实吗?它们可能会改变你对每一滴水的看法! Scientists have discovered something incredible - the amount of water on the Earth toda…...

AI自动化测试全攻略:从AI 自动化测试实战到AI 智能测试平台开发!

最新一期 AI + 全栈测试开发训练营震撼来袭,课程内容全面升级,月薪轻松对标 30k + !今日开放 5 个特价名额,零基础小白与测试老司机皆可在此找到专属学习路径,涵盖从AI 自动化测试实战到AI 智能测试平台开发等前沿内容,覆盖 AI 时代测试开发核心能力,帮你构建完整知识体…...

LG9691

考虑 dp。设 \(f_i\) 表示到位置 \(i\) 所需的最小花费,且第 \(i\) 个位置必选,现在要找上一个决策点 \(j\),这个点应该要在此前所有区间的左端点的后面,才能保证这些区间能被覆盖(即确保至少一个在之前每个区间内),则 \(j\) 应满足 \(\max_{r_k<i}l_k \le j < i\…...

即时通讯小程序 - 实践

即时通讯小程序 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 1…...

PHP serialize 序列化完全指南

PHP serialize 序列化完全指南 介绍 如果你和我一样,第一次在 PHP 中看到序列化字符串时会觉得很困惑。我当时在做一个 Laravel 项目,想搞清楚将任务推送到队列时到底发生了什么。我发现一些数据被序列化了,但不知道为什么以及怎么工作的。不过在我花时间研究序列化后,发现…...

CF2112D

注意到一条边无论方向如何,都能使两端的某一个点到达另一个点,即至少有 \(n-1\) 对。如果只需要 \(n-1\) 对,那么只需要在每一条链上相邻的边方向相反即可。对于剩下的一对,我们可以找到一个度数为 \(2\) 的点,并把连接的两条边由反向改为同向,那么附近的三个点产生的对数…...

CF2112C

设 Alice 取的位置为 \(i,j,k\) 且 \(i<j<k\),则 Bob 的最优策略有两种:取 \(n\) 或 \(k\)。为了使 Alice 必胜,必须同时满足 \(a_i+a_j+a_k>a_n,a_i+a_j>a_k\)。枚举 \(i,j\),显然满足两个条件的 \(k\) 都是一段连续的区间。分别二分算出两个区间的边界,那么…...

CF342C

显然,每一层恰好能放下两个球(事实上这也是最优的方案),那么下面一共可以放 \(\lfloor \frac{h}{r} \rfloor \times 2\) 个球,剩余 \(h - \lfloor \frac{h}{r} \rfloor \times r+r\) 的高度,记 \(h=h-\lfloor \frac{h}{r} \rfloor\times r\) 为立方体部分剩余高度。最上面…...

ICPC/XCPC 做题记录

[SNCPC2019] Unrooted Trie 发现不满足题意的情况就是一个节点到多个子节点的边的字母相同,那么合法当且仅当每个节点到子节点的字母互不相同。那么可以统计每个节点连接的字母数量,并运用类似换根 dp 的思路,快速更新这个数量并实时维护符合条件的点的数量即可。时间复杂度…...

LG9648

发现不满足题意的情况就是一个节点到多个子节点的边的字母相同,那么合法当且仅当每个节点到子节点的字母互不相同。那么可以统计每个节点连接的字母数量,并运用类似换根 dp 的思路,快速更新这个数量并实时维护符合条件的点的数量即可。时间复杂度 \(O(nA)\),其中 \(A=26\) …...

LG5689

设 \(f_u\) 表示以 \(u\) 为根的子树构成不同多叉堆的方案数。显然最小的 \(0\) 应该分配给 \(u\),剩下的分给子节点 \(v_1,v_2,\cdots,v_k\),根据乘法原理,有 \[f_u=\prod_{i=1}^k \binom{siz_u-1-\sum_{j=1}^{i-1}siz_{v_j}}{siz_{v_i}}f_{v_i} \]将组合数和 \(f\) 分开,…...

近五年 CSP NOIP 补题记录

2025.6.18 NOIP2024 T4 树上查询 To be updated. Submission CSP-S2019 江西 T3 网格图 To be updated. Submission 2025.6.19 CSP-S2019 D1T2 括号树 To be updated. Submission CSP-S2021 T3 回文 To be updated. Submission CSP-S2019 江西 T1 日期 To be updated. Submissi…...

CF2111C

显然,操作的方式一定是一段数字相等的极长连续段向左右拓展(包括长度为 \(1\) 的段)。故只需扫一遍并维护每段的值和长度即可,并更新答案。时间复杂度 \(O(\sum n)\)。 #include<iostream> #include<cstdio> #define int long long #define N 500010 using nam…...

唐人日记

唐注意看函数返回值!!!!!!!...

CF2111B

首先最大的 \(f_n\) 必须放的下,即 \(f_n \le \min(w,l,h)\)。此外,\(f_{n-1}\) 紧贴在 \(f_n\) 的一个面上,故要 \(f_n+f_{n-1} \le \max(w,l,h)\)。剩下的第 \(i\) 个正方体由于满足 \(f_{i+2}=f_{i}+f_{i+1}\),故只需与第 \(i+1,i+2\) 个正方体共用一条棱即可,且一定不…...

ABC394F

在同一棵树中,选择任意一个点作为根,效果都是相同的。不妨以 \(1\) 为树根,考虑树上 dp,记 \(f_u\) 为以 \(u\) 为根的子树的点数最大值。注意到根节点度数可为 \(1\) 可为 \(4\),而非根非叶子节点度数必须为 \(4\)。由此可以分两类转移。假设子树中 \(u\) 度数为 \(1\),…...

LG11793

注意到 \(N \times M \le 2\times 10^7\),因此不难得到一个 dp 做法。设 \(f_i\) 表示把前 \(i\) 个橙子装进箱子内的最小成本,则不难得到以下转移式: \[f_i=\min_{i-j\le m,0 \le j < i} f_j+k+ ( i - j ) \times ( \max_{j < k \le i} a_k - \min_{j < k \le i} …...

ABC394G

题目要求最小化爬楼梯的次数,那么我们就要让楼层的变化尽量小,即沿线楼房高度越高越好。不难发现影响答案的是路线中的楼房高度的最小值,则需要最大化最小值。那么就不难用 Kruskal 重构树做了。对每个点进行唯一编号,相邻的点建边权为较小的的楼房高度的双向边。剩下的就是…...

MX 炼石 2026 NOIP #5

qwq2026 --【炼石计划 NOIP】-- 第五套 链接:link 题解:link 时间:4h (2025.09.11 14:00~18:00) 题目数:4 难度:A B C D估分:[40,60] + 80 + 32 + ? = [152,172]+? 得分:40 + 60 + 32 + 10 = 142 Rank:场祭补题天依宝宝可爱!...

0126_状态模式(State)

状态模式(State) 意图 允许对象在内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 UML 图优点行为与状态绑定:将特定状态下的行为局部化到对应的状态类中 消除条件判断:避免了大量的if-else状态判断逻辑 状态转换明确:使状态转换流程更加清晰和可管理 易于扩展:…...

Visual Studio 2026 预览体验版现已发布,一起来看看带来哪些新功能!

前言 2025 年 9 月 9 日微软 Visual Studio 团队正式推出了 Visual Studio 2026 预览体验版(Visual Studio 2026 Insiders),此次发布标志着 Visual Studio 迎来一个全新的时代,它将人工智能深度集成到平台中,基础功能更强大,性能也得到进一步提升。 下载 Visual Studio 2…...

基于RK3568/RK3576/RK3588/全志H3/飞腾芯片/国产UOS等/国标GB28181监控系统

一、前言说明 之前从最底层协议通信把gb28181实现了一遍,没有用到exosip或者pjsip等任何第三方库,通过熟读gb28181国标文档几百页,看了一遍又一遍,根据对应的官方文档,一行行代码底层实现,其实就是网络通信,可选tcp或者udp,和http都是同类型的协议,有消息头和消息体,…...