【分块】余数求和

传送门

【题目】:

给你n,k;        \large \sum_{i=1}^{n}k\%n 

【题解】:

根据多个人的博客,我终于看懂了,其实就很简单,大家认真分析即可。

首先对这个式子进行一系列地化简:

\large \sum_{i=1}^{n}k\%n=\sum_{i=1}^{n}(k-\left \lfloor \frac{k}{i} \right \rfloor*i)

\large \sum_{i=1}^{n}(k-\left \lfloor \frac{k}{i} \right \rfloor*i)=n*k-\sum_{i=1}^{n}\left \lfloor \frac{k}{i} \right \rfloor*i

 

发现每一个位置i,整除k都会得到不同的值。

然后对于不同的值,进行分块处理。

对于每一块来说,都有左右端点。左端点L=i,那么右端点呢???

∵k/L=k/R

∴R=k/(k/L)

可能会出现k/L=0,此时加一个判断直接让R=n.

区间求和:等差数列求和。

暂存值:t=k/L

个数为:R-L+1

那么一段区间的值为:t*(R-L+1)*(L+R)/2

看代码呗;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k,ans;
int main()
{
    ios_base :: sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> n >> k;

    for ( int L=1 , R ; L<=n ; L=R+1 ){
        ll tmp = k/L;
        R = tmp ? min( k/tmp , n) : n;
        ans = ans + tmp* ( R - L + 1 )*(L+R)/2;
    }
    ans = n*k - ans;
    cout<<ans<<endl;
    return 0;
}

 

<think>我们正在讨论嵌入式C语言开发中的数据分块处理。数据分块处理是一种常见的技术,特别是在处理大量数据或资源受限的嵌入式系统中。分块处理可以将大数据分割成小块,逐块处理,从而减少内存占用,提高系统响应性,并允许在块之间执行其他任务(如通信或用户交互)。 参考引用: - 引用[2]提到了嵌入式系统的硬件基础、存储系统和软件架构,这些是设计分块处理时需要考虑的背景。 - 引用[3]提供了一个线程池的示例,线程池可以用于并行处理数据块,提高处理效率。 - 引用[4]展示了数字滤波器的实现,其中涉及对数组数据的处理,这种处理可以应用分块技术。 实现数据分块处理的方法通常包括: 1. 将数据分割成固定大小的块。 2. 设计处理函数,该函数能够处理一个数据块。 3. 循环或并行地处理每个数据块。 具体步骤和示例代码: ### 1. 数据分块 假设我们有一个大型数据数组,我们将其分成多个小块。每个块的大小可以根据可用内存和处理需求来确定。 ```c #define BLOCK_SIZE 256 #define TOTAL_DATA_SIZE 1024 // 假设这是原始数据 uint8_t raw_data[TOTAL_DATA_SIZE]; // 分块处理:计算块的数量 int num_blocks = TOTAL_DATA_SIZE / BLOCK_SIZE; if (TOTAL_DATA_SIZE % BLOCK_SIZE != 0) { num_blocks++; // 如果有余数,增加一个块 } ``` ### 2. 处理单个数据块 编写一个函数,用于处理单个数据块。例如,我们可以对每个块进行某种计算(如求和、滤波等)。 ```c void process_block(uint8_t *block, size_t size) { for (int i = 0; i < size; i++) { // 示例处理:简单地将每个元素乘以2 block[i] = block[i] * 2; } } ``` ### 3. 循环处理所有块 在主程序中,循环遍历每个块,并调用处理函数。 ```c for (int block_idx = 0; block_idx < num_blocks; block_idx++) { // 计算当前块的起始位置 uint8_t *block_start = raw_data + (block_idx * BLOCK_SIZE); // 计算当前块的实际大小(最后一个块可能不满) size_t current_block_size = BLOCK_SIZE; if (block_idx == num_blocks - 1 && TOTAL_DATA_SIZE % BLOCK_SIZE != 0) { current_block_size = TOTAL_DATA_SIZE % BLOCK_SIZE; } // 处理当前块 process_block(block_start, current_block_size); } ``` ### 4. 使用多线程或线程池并行处理(可选) 在支持多线程的嵌入式系统中(如使用RTOS或pthread),我们可以利用线程池来并行处理多个数据块,提高处理速度。引用[3]中的线程池示例可以用于此目的。 修改上面的循环,将每个块的处理作为一个任务添加到线程池中: ```c // 假设线程池已经初始化 thread_pool_t pool; thread_pool_init(&pool, 4); // 4个线程 for (int block_idx = 0; block_idx < num_blocks; block_idx++) { // 为每个块创建一个任务参数结构(这里简化,直接传递块信息) block_task_param_t *param = (block_task_param_t*)malloc(sizeof(block_task_param_t)); param->block_start = raw_data + (block_idx * BLOCK_SIZE); param->block_size = (block_idx == num_blocks - 1 && TOTAL_DATA_SIZE % BLOCK_SIZE != 0) ? (TOTAL_DATA_SIZE % BLOCK_SIZE) : BLOCK_SIZE; // 将任务添加到线程池 thread_pool_add_task(&pool, process_block_task, param); } // 等待所有任务完成 // 这里需要根据线程池的实现来等待,例如使用条件变量 // 然后销毁线程池 ``` 其中,`process_block_task`函数是对`process_block`的封装,以便作为线程任务: ```c void process_block_task(void *arg) { block_task_param_t *param = (block_task_param_t*)arg; process_block(param->block_start, param->block_size); free(param); // 释放参数内存 } ``` ### 注意事项 - **内存管理**:在嵌入式系统中,动态内存分配(如`malloc`)可能带来碎片问题,因此可以考虑使用静态分配或内存池。 - **块大小**:块大小的选择需要权衡内存占用和处理效率。块太小会导致过多的任务切换开销,块太大可能无法放入内存。 - **数据依赖**:如果块之间存在数据依赖,需要设计重叠区域或处理顺序。 - **实时性**:在实时系统中,分块处理可能引入延迟,需要评估最坏执行时间。 ### 实际应用 在引用[4]的数字滤波器中,如果数据量很大,也可以采用分块处理。例如,将输入数据分成多个块,逐块应用LMS滤波算法。 ### 总结 在嵌入式C语言中实现数据分块处理,主要步骤包括数据分块、设计块处理函数、循环或并行处理块。这种方法有助于管理内存和计算资源,特别适合资源受限的嵌入式系统。 §§相关问题§§ 1. 在嵌入式系统中,如何选择合适的数据块大小? 2. 如何处理分块数据之间的依赖关系? 3. 在实时操作系统中如何实现数据分块处理的优先级调度? 4. 嵌入式系统中分块处理有哪些常见应用场景?</think>### 嵌入式C语言数据分块处理实现指南 在嵌入式系统中实现数据分块处理是优化内存使用和提高效率的关键技术,尤其适合资源受限的环境。以下是具体实现方法和示例: #### 一、核心实现原理 1. **分块策略**: - 固定大小分块:`#define BLOCK_SIZE 256` - 动态分块:根据可用内存动态调整块大小 - 循环缓冲区:`uint8_t circular_buffer[2][BLOCK_SIZE]` 2. **处理流程**: ```mermaid graph TD A[原始数据流] --> B{数据分块} B --> C[块1处理] B --> D[块2处理] C --> E[结果存储] D --> E E --> F[下一轮处理] ``` #### 二、具体实现方法 ##### 方法1:静态分块处理 ```c #define BLOCK_SIZE 512 // 根据内存限制调整 #define TOTAL_DATA_SIZE 4096 void process_block(uint8_t *block, size_t size) { // 块处理逻辑(如滤波/变换) for (int i = 0; i < size; i++) { block[i] = digital_filter(block[i]); // 示例处理 } } int main() { uint8_t data[TOTAL_DATA_SIZE]; size_t blocks = TOTAL_DATA_SIZE / BLOCK_SIZE; for (int i = 0; i < blocks; i++) { process_block(&data[i * BLOCK_SIZE], BLOCK_SIZE); // 可在此处添加任务切换点 } return 0; } ``` ##### 方法2:双缓冲机制(实时流处理) ```c uint8_t buffer[2][BLOCK_SIZE]; // 双缓冲 volatile int active_buf = 0; // 当前活动缓冲区 // 中断服务程序(数据采集) void ADC_ISR() { static int index = 0; buffer[active_buf][index++] = read_adc(); if (index >= BLOCK_SIZE) { index = 0; active_buf ^= 1; // 切换缓冲区 set_processing_flag(); // 通知主程序 } } // 主循环 while(1) { if (processing_flag) { int process_buf = active_buf ^ 1; // 处理非活动缓冲区 process_block(buffer[process_buf], BLOCK_SIZE); clear_processing_flag(); } // 其他任务... } ``` ##### 方法3:使用线程池并行处理(引用[3]技术) ```c void block_processing_task(void* arg) { BlockData* block = (BlockData*)arg; // 执行块处理... free(block); } int main() { thread_pool_t pool; thread_pool_init(&pool, 2); // 2个工作线程 while(data_available) { BlockData* block = malloc(sizeof(BlockData)); load_data_block(block); // 加载数据块 thread_pool_add_task(&pool, block_processing_task, block); } thread_pool_destroy(&pool); return 0; } ``` #### 三、关键优化技术 1. **内存管理**: - 使用静态分配避免碎片:`static uint8_t block_memory[MAX_BLOCKS][BLOCK_SIZE]` - 内存池技术:预分配固定大小内存块 2. **DMA传输优化**: ```c // 配置DMA实现零拷贝传输 HAL_DMA_Start(&hdma_adc, (uint32_t)&ADC1->DR, (uint32_t)buffer[active_buf], BLOCK_SIZE); ``` 3. **性能平衡公式**: 块大小选择原则: $$ T_{process} \leq T_{acquire} + T_{margin} $$ 其中: - $T_{process}$ = 块处理时间 - $T_{acquire}$ = 下一块数据采集时间 - $T_{margin}$ = 安全裕量 #### 四、应用场景 1. **实时信号处理**(引用[4]): - 分块应用FIR/IIR滤波器 - 分段计算FFT频谱分析 2. **大文件存储**: ```c while(fread(block, 1, BLOCK_SIZE, fp) > 0) { flash_write_block(block, BLOCK_SIZE); } ``` 3. **通信协议处理**: - 分块解析Modbus/TCP帧 - 分段处理CAN总线消息队列 #### 五、注意事项 1. **边界处理**: ```c size_t remaining = total_size - position; size_t current_block = (remaining > BLOCK_SIZE) ? BLOCK_SIZE : remaining; ``` 2. **数据一致性**: - 使用临界区保护共享缓冲区 - 内存屏障确保数据可见性:`__DSB()`(ARM Cortex-M) 3. **性能监控**: - 通过定时器测量块处理时间 - 使用RTOS任务监控栈使用情况 > **实践建议**:在STM32等MCU上,结合DMA和双缓冲技术可实现高效数据处理,典型块大小通常设为外设缓冲区大小的整数倍(如ADC的DMA缓冲区)[^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值