51nod 1421 最大MOD值 codeforce 484B. Maximum Value【调和级数复杂度T_T】

本文深入探讨了算法优化技巧,特别是在解决特定问题时如何利用数据结构和算法进行高效求解。通过实例分析,展示了如何使用哈希表和二分查找等技术减少复杂度,以及如何在竞赛中快速定位最优解。同时,文章对比了两种不同优化策略的效果,指出预处理数据可以显著提升运行效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

题目链接:

51nod 1421
cf484B

参考博客:https://blog.youkuaiyun.com/linkfqy/article/details/78300976
对哈,里面那层循环的复杂度是调和级数,数越大枚举这个数的倍数就越小

然后就是找一段范围内最大的数,最开始竟然没有反应过来,就是找这段范围的最右边看在哪里,他的左边一个不就是这段范围里最大的嘛~

#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
int a[maxn];
int main()
{
	int N;
	while(cin>>N)
	{
		int ans=0;
		for(int i=1;i<=N;i++)scanf("%d",a+i);
		sort(a+1,a+1+N);
		for(int i=1;i<=N;i++)
		{
			if(a[i]==a[i-1])continue;//只要第一个来判断 
			for(int k=2;k*a[i]<=a[N];k++)
			{
				int pos=lower_bound(a+1,a+1+N,k*a[i])-a;
				ans=max(ans,a[pos-1]%a[i]);//找到a[pos]这个数,再往前面一个数a[pos-1]肯定在[k*ai,(k+1)*ai]范围内 
			}
			ans=max(ans,a[N]%a[i]);//剩下不够倍数的一段,最后的是最大的 
		}
		cout<<ans<<endl;
	}
}

然后就是因为 a i a_i ai的数据范围是1e6,所以阔以用个数组b[i]来保存小于 i 的最大的a[]数组中的数是多少,这样中间那层二分就变成 O ( 1 ) O(1) O(1)的了。用这种方法只跑了109ms,而上面二分那个跑路608ms,优化很明显呀~

#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
int a[maxn],b[maxn*5];//b[i]表示a[]数组中比i小的最大的数 
int main()
{
	int N;
	while(cin>>N)
	{
		int ans=0;
		for(int i=1;i<=N;i++)scanf("%d",a+i);
		sort(a+1,a+1+N);
		N=unique(a+1,a+1+N)-(a+1);
		for(int i=1,j=0;i<=1000000;)
		{
			if(i>a[j]&&i<=a[j+1])b[i++]=a[j];
			else if(j==N)b[i++]=a[N];
			else j++;
		}
		for(int i=1;i<=N;i++)
		{
			for(int k=2;k*a[i]<=a[N];k++)
			{
				ans=max(ans,b[k*a[i]]%a[i]);
			}
			ans=max(ans,a[N]%a[i]);//剩下不够倍数的一段,最后的是最大的 
		}
		cout<<ans<<endl;
	}
}
<think>首先,用户的问题是:"我想解决在STM32项目链接过程中出现的符号重复定义错误(delay_us) 请问STM32 link error L6200E Symbol delay_us multiply defined by ds18b20.o and sys.o"。这是一个链接错误,具体是符号`delay_us`在`ds18b20.o`和`sys.o`中都被定义了。 从系统级指令中,我需要: - 所有行内数学表达式使用`$...$`格式。 - 独立公式使用`$$...$$`格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 参考站内引用:用户提供了几个引用,我需要参考它们。 站内引用: - [^1]: 解决`__stdout`重复定义的问题,通过勾选Use MicroLIB。 - [^2]: 解决`rr`重复定义的问题,建议在`.c`文件中定义变量,在头文件中使用`extern`声明。 - [^3]: 类似[^2],解决`rgb`重复定义的问题,强调不要在头文件中定义变量,应该在`.c`文件中定义,并在其他地方使用`extern`。 - [^4]: 解决`__stdout`重复定义的问题,由于在多个地方定义了符号。 用户的问题是关于`delay_us`符号的重复定义,错误消息是:`Symbol delay_us multiply defined by ds18b20.o and sys.o`。这表明`delay_us`函数在两个目标文件中都被定义了。 关键点: - 在C语言中,函数或变量只能在一个地方定义(在`.c`文件中),但可以在多个地方声明(在`.h`文件中使用`extern`)。 - 错误通常发生在函数定义被放在头文件中,或者多个源文件包含了相同的定义。 解决方案思路: 1. 检查`delay_us`函数的定义位置。它应该在`.c`文件中定义一次。 2. 在头文件中,应该使用`extern`声明函数,而不是定义它。 3. 确保没有多个源文件定义了相同的函数。 从引用[^2]和[^3]中,核心建议是: - 不要在头文件中定义变量或函数。 - 在`.c`文件中定义变量或函数。 - 在头文件中使用`extern`声明它们。 所以,对于用户的问题: - `delay_us`可能是一个函数(假设是微秒延时函数)。 - 它被定义在`ds18b20.c`和`sys.c`中?或者可能是在头文件中被包含多次。 用户说错误是`by ds18b20.o and sys.o`,这意味着`ds18b20.c`和`sys.c`都包含了`delay_us`的定义。 可能的原因: - `delay_us`函数在头文件(如`delay.h`)中被定义(例如,直接写函数体),而不是声明。 - 或者,它在多个`.c`文件中被定义了。 解决方案步骤: 1. 找到`delay_us`的定义位置。 2. 如果它在头文件中定义,移到一个`.c`文件中(例如,`delay.c`),并在头文件中改为`extern`声明。 3. 如果它在多个`.c`文件中定义,只保留一个定义,其他地方使用声明。 在回答中,我需要结构清晰,逐步指导用户。 生成相关问题:在回答结束后,添加相关问题部分。 使用中文回答。 现在,构建回答: - 开头解释错误。 - 分析原因。 - 提供解决方案步骤。 - 参考引用。 引用相关部分: - 引用[^2]:建议在`.c`文件中定义变量,在头文件中使用`extern`。 - 引用[^3]:类似,强调不要在头文件中定义。 所以,在回答中,可以自然地引用这些。 最终回答结构: 1. **解释错误**:简要说明链接错误的原因。 2. **原因分析**:为什么会出现重复定义。 3. **解决方案**:逐步指导如何解决。 4. **示例代码**:如果需要,展示如何修改头文件和源文件。 5. **相关问题**:生成几个相关问题。 相关问题: - 如何避免在STM32项目中符号重复定义? - 什么是extern关键字的作用? - 如何正确组织STM32项目的头文件和源文件? 确保LaTeX格式:如果有数学表达式,用`$...$`或`$$...$$`。但在这个问题中,可能不需要数学表达式,除非讨论时间延迟等。 用户的问题是关于`delay_us`,可能涉及时间计算,但错误是链接错误,所以可能不需要数学。如果需要,可以添加。 例如,如果讨论延时函数,可以提到微秒延时,但错误本身是编程问题。 现在,草拟回答。</think>### STM32链接错误 L6200E: Symbol delay_us multiply defined 的解决方案 在STM32开发中,链接错误 `Error: L6200E: Symbol delay_us multiply defined by ds18b20.o and sys.o` 表示符号 `delay_us`(通常是一个微秒延时函数)在多个目标文件中被重复定义。这会导致链接器无法确定使用哪个定义,从而中断编译过程。本回答将逐步分析原因并提供解决方案,确保代码结构正确。参考您的项目描述和站内引用,以下是详细指导。 --- ### 错误原因分析 1. **重复定义的本质**: 在C语言中,函数或全局变量只能在一个源文件(`.c`文件)中定义一次。如果 `delay_us` 在 `ds18b20.c` 和 `sys.c` 中都包含完整定义(例如函数体),链接时就会冲突。常见原因包括: - **头文件错误定义**:`delay_us` 在头文件(如 `delay.h`)中被直接定义(而非声明),导致所有包含该头文件的源文件都拥有其副本。 - **多文件定义**:`delay_us` 在 `ds18b20.c` 和 `sys.c` 中均被实现,违反“单一定义规则”。 - **缺少 `extern` 声明**:在头文件中未使用 `extern` 声明符号,导致包含头文件的源文件误认为需要本地定义。 2. **引用参考**: 类似问题在站内引用中多次出现。例如,引用[^2]和[^3]强调:变量或函数定义应放在 `.c` 文件中,头文件仅用于 `extern` 声明,否则会因多次包含引发重复定义[^2][^3]。引用[^4]也指出,符号冲突常因多个模块定义相同符号所致[^4]。 --- ### 解决方案步骤 按照以下步骤检查和修复代码,确保 `delay_us` 只定义一次: #### 步骤1: 定位符号定义位置 - **全局搜索 `delay_us`**:在Keil MDK或其他IDE中,使用 `Ctrl+F` 搜索整个工程,检查 `delay_us` 的定义位置(即包含函数体或变量初始化的地方)。 - **预期结果**: - 正确:`delay_us` 应只在一个 `.c` 文件中定义(如 `sys.c` 或新建 `delay.c`)。 - 错误:如果在头文件(`.h`)或多于一个 `.c` 文件中找到定义,需修改。 #### 步骤2: 修改头文件(使用 `extern` 声明) - **问题场景**:如果 `delay_us` 在头文件(如 `delay.h`)中被定义,例如: ```c // delay.h (错误示例) void delay_us(uint32_t us) { // 函数实现 } ``` - **修复方法**: - 将定义移到 `.c` 文件(如 `sys.c`)。 - 在头文件中改为 `extern` 声明(仅提供函数原型): ```c // delay.h (正确示例) #ifndef DELAY_H #define DELAY_H extern void delay_us(uint32_t us); // 使用 extern 声明 #endif ``` 参考引用[^3]:头文件中的定义会导致所有包含它的源文件重复定义,必须移至 `.c` 文件[^3]。 #### 步骤3: 确保单一源文件定义 - **问题场景**:如果 `delay_us` 在 `ds18b20.c` 和 `sys.c` 中均有实现: ```c // ds18b20.c (错误示例) void delay_us(uint32_t us) { // DS18B20 相关延时实现 } // sys.c (错误示例) void delay_us(uint32_t us) { // 系统级延时实现 } ``` - **修复方法**: - 保留一个定义(建议在公共模块如 `sys.c`),删除其他定义。 - 在需要调用的文件(如 `ds18b20.c`)中,通过头文件引入声明: ```c // ds18b20.c (正确示例) #include "delay.h" // 引入 extern 声明 void ds18b20_read() { delay_us(10); // 调用延时 } ``` 参考引用[^2]:变量或函数应在 `.c` 中定义,其他文件通过 `extern` 使用[^2]。 #### 步骤4: 检查文件包含关系 - **避免循环包含**:确保头文件使用 `#ifndef`/`#define` 宏防止重复包含(如步骤2示例)。 - **验证链接**:编译后,如果仍有错误,检查: - 所有源文件只包含声明头文件(如 `delay.h`),而非直接定义。 - 未在 `.c` 文件中重复定义 `delay_us`。 #### 步骤5: 示例代码结构 以下是一个修复后的简化示例: ```c // delay.h #ifndef DELAY_H #define DELAY_H #include <stdint.h> extern void delay_us(uint32_t us); // 声明 #endif // sys.c #include "delay.h" void delay_us(uint32_t us) { // 基于系统时钟实现微秒延时,例如使用SysTick // 例如:计算延时周期数 $n = \text{us} \times \text{CPU\_Freq} / 10^6$ // 实际代码省略... } // ds18b20.c #include "delay.h" #include "ds18b20.h" void ds18b20_init() { delay_us(1000); // 正确调用 } ``` --- ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值