RCC 2014 Warmup (Div. 2)

本文提供了一场 CodeForces 比赛(编号 417)的解题报告,包括 A 到 E 题的详细解析及代码实现。涉及主题有简单数学、模拟算法、构造算法、状态压缩 DP 和矩阵构造。

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

题目链接:http://codeforces.com/contest/417 

这可能是算很简单的一场CF了。

A题:大意是要让一些人进决赛, 有两种方式一种是C道题,晋级n个人, 还有一种是d道题, 晋级1个人, 现在给出要晋级的人数, 求最少需要多少道题目。 计算几种可能的情况, 比较一下即可。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int c, d, m, n, k;

int main(){
    scanf("%d%d%d%d%d", &c, &d, &n, &m, &k);
    int x, y;
    int res = (m*n) - k;
    if(res < 0) res = 0;
    x = res*d;
    y = res/n * c;
    if(res % n != 0){
        int n1 = y + c;
        int n2 = y + (res%n) * d;
        y = n1 < n2 ? n1 : n2;
    }
    printf("%d\n", x < y? x : y);
    return 0;
}


B题:大意是描述了某个系统后台处理数据的模式, 对于每个用户K有相同ID来标记相同的code. 我们要确定的是, 对于某个用户K在出现标记为X的代码时, X-1标号的代码必须要出现过。 模拟即可

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N];

int main(){
    int n;
    scanf("%d", &n);
    bool suc = 1;
    memset(a, -1, sizeof(a));
    while(n--){
        int x, k;
        scanf("%d%d", &x, &k);
        if(suc == 0) continue;
        if(x == 0 && a[k] == -1) a[k] = 0;
        else{
            if(x <= a[k]) continue;
            else if(x == a[k] + 1) a[k] = x;
            else suc = 0;
        }
    }
    if(suc) printf("YES\n");
    else printf("NO\n");
    return 0;
}


C题:一个简单的构造题。 题意是:有n个球队互相踢比赛, 每两个球队之间最多踢一场比赛, 现在已知每支球队都踢了K场比赛, 构造一种可能的情况。 首先N支球队最多踢n*(n-1)/2场比赛, 先预判断一下n*k是否超过这个数字。

如果没超过我们可以这样构造: 球队1与2,3...踢, 球队2与3,4...踢,...... 球队n与1,2..踢,依此构造。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

int main(){
    int n, k;
    scanf("%d%d", &n, &k);
    int t = n*(n-1)/2;
    if(n*k > t) printf("-1\n");
    else{
        printf("%d\n", n*k);
        for(int i = 1; i <= n; ++i){
            for(int j = i + 1; j <= i + k; ++j){
                printf("%d %d\n", i, (j-1)%n + 1);
            }
        }
    }
    return 0;
}


D题:稍微困难, 状态压缩DP。 题意是某人有n个朋友, 要请他们完成m道题目(m < 20), 每个朋友帮忙都有要求, 一是要求有n个显示屏, 二是要给x卢布(RUS)的报酬, 每个显示屏b元, 给出每个朋友能做出的题目具体编号, 求要做出所有题目要花多少钱。 考虑到m较小, 我们可以用状态压缩DP来解决。 由于显示器可以分时复用,所以我们可以先将所有朋友按显示器个数从小到大排序,这样到后面选择的时候可以保证前面所选的人可以肯定有足够的显示器支持。 状态压缩DP显然向后DP比较方便。同时要注意数据的范围。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = (1<<20) | 0x10;
const LL INF = ((LL)1 << 60);
LL f[N];
int n, m;
LL b;
struct node{
    int x, n;
    int slo;
}a[110];

bool cmp(node a, node b){
    return a.n < b.n;
}

int main(){
    scanf("%d%d%I64d", &n, &m, &b);
    for(int i = 0; i < n; ++i){
        int x, k, t;
        scanf("%d%d%d", &a[i].x, &a[i].n, &t);
        for(int j = 0; j < t; ++j){
            int num;
            scanf("%d", &num);
            a[i].slo |= 1 << (num - 1);
        }
    }

    sort(a, a + n, cmp);
   // memset(f, INF, sizeof(INF));
    for(int i = 1; i < (1<<m); ++i){
        f[i] = INF;
    }
    LL ans = INF;
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < (1<<m); ++j){
            LL tmp = (LL)a[i].x + f[j];
            if(tmp < f[j|a[i].slo])
                f[j|a[i].slo] = tmp;
        }
        if(ans > f[(1 << m) - 1] + a[i].n * b)
            ans = f[(1 << m) - 1] + a[i].n * b;
    }
    if(ans == INF) ans = -1;
    printf("%lld\n", ans);
    return 0;
}



E题:看了别人的思路。 同样是一道构造题。用到了矩阵的知识。 给出m, n 要求构造出一个矩阵满足, 每一行每一列的数平方和都是一个完全平方数。 思路很巧。 考虑到m*1和1*n的两个矩阵, 假如这两个矩阵都满足平方和为完全平方数的话, 那么这两个矩阵的乘积就是一个满足条件的矩阵(自己试试看)。问题转化为给出一个n,如何构造n个数使他们的平方和为完全平方数。 考虑这个等式:(n-1)+ (n/2 - 1)^2 = (n/2)^2; 由此可知, 在n等于偶数的情况下,n-1个1 和 一个 (n/2-1)可以构造成功。 如果n是奇数如何解决?可以将其中的一个1变成2,那么通过调整之后可以知道(n+1)/2 , 2, n-2满足条件。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N = 110;
int a[N], b[N];

void gao(int n, int *a){
    if(n == 1) a[0] = 1;
    else if(n == 2){
        a[0] = 3;
        a[1] = 4;
    }
    else{
        if(n & 1){
            for(int i = 0; i < n - 2; ++i) a[i] = 1;
            a[n-2] = 2;
            a[n-1] = (n >> 1) + 1;
        }
        else{
            for(int i = 0; i < n - 1; ++i) a[i] = 1;
            a[n-1] = (n >> 1) - 1;
        }
    }
}

int main(){
    int n, m;
    scanf("%d%d", &m, &n);
    gao(m, a);
    gao(n, b);
    for(int i = 0; i < m; ++i){
        for(int j = 0; j < n; ++j)
            printf("%d ", a[i]*b[j]);
        printf("\n");
    }
    return 0;
}



<think>好的,我现在要帮用户解决关于STM32外部晶振配置的问题。用户提到他们用的是8MHz的外部晶振(HSE),并给出了他们的RCC配置代码。我需要先理解他们的配置是否正确,并解释各个参数的作用。 首先,用户提供的代码片段是关于RCC(复位和时钟控制)的初始化结构体设置。他们配置了HSE和LSI作为振荡器类型,启用了HSE和LSI,并且配置了PLL。用户可能想知道这样的配置是否正确,或者他们的系统时钟是如何计算的,特别是当外部晶振是8MHz时。 我需要逐步分析他们的配置参数。首先,用户启用了HSE和LSI。HSE是外部高速晶振,这里设置为8MHz,LSI是内部低速RC振荡器,通常用于看门狗或RTC。不过,在大多数情况下,系统时钟源不会同时使用HSE和LSI,可能用户有其他需求,比如RTC需要LSI,但主要系统时钟来自HSE和PLL。 接下来是PLL的配置。PLL的源是HSE,也就是8MHz。PLLM分频系数设置为1,所以输入到PLL的时钟是8MHz / 1 = 8MHz。PLLN是乘法因子,设置为16,因此VCO输出频率是8MHz * 16 = 128MHz。然后PLLP分频系数是2,所以PLL的P输出是128MHz / 2 = 64MHz,这通常作为系统时钟(SYSCLK)。而PLLR分频系数设置为2,可能用于其他外设,比如USB或SDIO,但需要具体看芯片的支持情况。 这里可能存在一个问题:如果用户的目标是得到更高的系统时钟,比如常见的72MHz或84MHz,这样的配置可能不够。或者他们是否有特定的需求需要64MHz?另外,需要确认芯片是否支持这些分频系数,例如PLLN的范围通常在特定区间内,不同型号的STM32可能有不同的限制。 另外,用户是否在代码中正确设置了HSE_VALUE为8000000?如果头文件中的定义与实际晶振不符,会导致时钟配置错误,进而影响整个系统的工作,比如串口波特率不正确,定时器时间不准等。 还需要检查系统时钟源的选择。用户可能在SystemClock_Config函数中设置了SYSCLK的来源为PLL,这样才能使用PLL的输出作为系统时钟。如果他们没有正确设置,即使PLL配置正确,系统时钟可能还是来自HSI或其他源。 总结用户的配置是否正确:假设他们使用的是STM32F4系列,PLLP分频系数为2是允许的,而PLLN=16可能过小,导致VCO频率不足。例如,STM32F4的VCO输入频率范围通常为1-2MHz,VCO输出频率需要介于192-432MHz之间。如果用户的HSE是8MHz,经过PLLM=1分频后,输入VCO是8MHz,乘以PLLN=16得到128MHz,这低于VCO的最低要求,会导致配置错误。因此,用户的配置可能存在错误,导致无法正常工作。 可能的解决方案是调整PLLM、PLLN和PLLP的值,使得VCO输入在1-2MHz之间,VCO输出在192-432MHz之间。例如,设置PLLM=8,这样HSE 8MHz /8 =1MHz,然后PLLN=192,得到VCO 192MHz,再PLLP=2,得到系统时钟96MHz。这样配置就符合要求了。 用户可能需要了解如何正确配置PLL参数,以及他们的目标系统时钟是多少。需要引导他们检查数据手册中关于时钟树的部分,确认各个分频系数的取值范围,并根据目标频率重新计算参数。此外,提醒他们在CubeMX中正确配置时钟,可以自动生成正确的代码,避免手动计算的错误。</think>--- ### **基于8MHz HSE的时钟配置解析** 您提供的代码片段是典型的STM32时钟树配置,以下将分步骤解析各参数含义及最终系统时钟计算结果: --- #### **1. 基础配置项解析** ```c RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; // 启用8MHz外部晶振 RCC_OscInitStruct.LSIState = RCC_LSI_ON; // 启用内部低速RC(约32kHz) ``` --- #### **2. PLL配置关键参数** ```c RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL时钟源=8MHz HSE RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1; // 分频系数M=1 RCC_OscInitStruct.PLL.PLLN = 16; // 倍频系数N=16 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // P分频系数=2 RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // R分频系数=2 ``` --- #### **3. 时钟计算流程** **PLL输入时钟**: $$ f_{in} = \frac{HSE}{PLLM} = \frac{8MHz}{1} = 8MHz $$ **VCO输出频率**: $$ f_{VCO} = f_{in} \times PLLN = 8MHz \times 16 = 128MHz $$ **系统时钟(SYSCLK)**: $$ f_{sys} = \frac{f_{VCO}}{PLLP} = \frac{128MHz}{2} = 64MHz $$ **其他时钟输出(如USB)**: $$ f_{R} = \frac{f_{VCO}}{PLLR} = \frac{128MHz}{2} = 64MHz $$ --- #### **4. 配置有效性验证** | 参数 | STM32F4允许范围 | 当前值 | 是否合规 | |------------|----------------|--------|----------| | PLLM | 1 ≤ M ≤ 63 | 1 | ✔ | | PLLN | 192 ≤ N ≤ 432 | 16 | ❌(严重过低) | | VCO输入频率 | 1-2MHz | 8MHz | ❌(超限) | | VCO输出频率 | 192-432MHz | 128MHz | ❌ | --- ### **发现问题与改进建议** **问题根源**: PLLN设置过低导致VCO输出频率不足,实际配置会产生硬件错误(HardFault) **修正方案**(以目标SYSCLK=64MHz为例): 1. 调整PLLM分频器: $$ PLLM = 8 \quad \Rightarrow \quad f_{in} = 8MHz/8 = 1MHz $$ 2. 重新计算PLLN: $$ PLLN = \frac{f_{sys} \times PLLP}{f_{in}} = \frac{64MHz \times 2}{1MHz} = 128 $$ 3. 验证VCO范围: $$ f_{VCO} = 1MHz \times 128 = 128MHz \quad (仍需调整) $$ 4. 最终合规配置: ```c RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV8; // 分频系数8 RCC_OscInitStruct.PLL.PLLN = 336; // 倍频系数336 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; // 分频系数4 ``` $$ f_{sys} = \frac{8MHz}{8} \times 336 \div 4 = 84MHz $$ --- ### **配置要点总结** 1. **VCO输入必须严格在1-2MHz之间** 2. **PLLN取值范围需满足芯片型号要求** 3. **建议使用STM32CubeMX自动生成配置代码** 4. **实际测试时用示波器测量PC13(HSI_OUT)验证时钟频率** --- **操作验证步骤**: 1. 在`main()`函数初始化后添加: ```c printf("System Clock: %lu Hz\n", HAL_RCC_GetSysClockFreq()); ``` 2. 通过SWD接口读取`SystemCoreClock`全局变量值 > 📌 注意:错误的PLL配置可能导致芯片无法正常运行,建议在修改后使用ST-Link Utility读取时钟寄存器验证实际频率
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值