牛客练习赛138(首篇万字题解???)

别再模拟IIC了!用STM32F103C8T6的硬件IIC驱动AT24C64,CubeMX配置+避坑指南 本文详细介绍了如何使用STM32F103C8T6的硬件IIC驱动AT24C64 EEPROM,通过CubeMX配置和HAL库函数解析,提供从模拟IIC到硬件IIC的完整解决方案。内容包括硬件IIC与模拟IIC的核心差异、CubeMX工程配置详解、HAL库驱动实战以及典型问题诊断与优化,帮助开发者构建更稳定高效的存储系统。 阅读详情

赛时成绩如下:

 1. 小s的签到题

小s拿到了一个比赛榜单,他要用最快的速度找到签到题,但是小s脑子还是有点晕,请你帮帮小s,助力他找到签到题。
比赛榜单是一个 2 行 n 列的表格:
第一行是 n 个大写字母,代表题号;
第二行是 n 个字符串,对应每一道题目的通过人数和提交人数,字符串由两个整数构成,整数之间使用字符 ‘/’ 隔开。
我们定义,通过人数最多的题目是签到题。请你找到签到题的题号并输出。特别地,如果有多个签到题,输出题号字母表顺序最小的那道。

输入描述:

第一行输入一个正整数 n(2≤n≤26),表示题目数量。
第二行输入 n 个两两不同的大写字母,表示每一道题的题号。
第三行输入 n 个字符串,表示每一道题的通过人数和提交人数。每个字符串格式为 a/b,其中 a 表示通过人数,b 表示提交人数。保证 0≤a≤b≤10^9
输出描述:
输出一个大写字母,表示签到题的题号。
示例1
输入
11
A B C D E F G H I J K
116/212 3/12 117/282 15/35 90/419 7/44 83/446 48/150 35/229 25/116 5/10
输出
C

解题思路:只需要比较a的大小, 然后记录下标, 输出A相对于下标的偏移量后字符即可(其实第二行输入没什么用)

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin >> n;
    vector<char> ids(n);
    for(int i = 0; i < n; i++){
        cin >> ids[i];
    }
    string s=""; int maxIdx=0;
    cin>>s;
    long long pos=s.find('/');
    string a=s.substr(0,pos);
    for(int i=1;i<n;i++){
        cin>>s;
        long long pos=s.find('/');
        string tmp=s.substr(0,pos); //字符串比较的是字典序而非大小
        if(stoll(tmp)>stoll(a)){
            a=tmp;
            maxIdx=i;
        }
    }
    cout<<(char)('A'+maxIdx)<<endl;
    return 0;
}

 2. 行列改写

题目描述

小柒最近获得了一个长度为 n 的数组 {r1,r2,…,rn} 和一个长度为 m 的数组 {c1,c2,…,cm}。他想用这两个数组来生成一个 n 行 m 列的二维数组,初始时,二维数组中每个元素的值均为 0,随后,他一共会进行 n+m 次操作,每次操作从以下两种覆盖方式中选择一种进行:
行覆盖:选择一个未被选中过的行,记为 i,将第 i 行的所有元素变为 ri​;
∙列覆盖:选择一个未被选中过的列,记为 j,将第 j 列的所有元素变为 cj​。
小柒希望最终的二维数组中所有元素之和最大,请你帮他计算这个最大值。

输入描述:

第一行输入两个正整数 n,m(1≤n,m≤105)代表 r 数组和 c 数组的长度。 
第二行输入 n 个正整数 r1,r2,…,rn(1≤ri≤106)代表 r 数组的数值。 
第三行输入 m 个正整数 c1,c2,…,cm(1≤ci≤106)代表 c 数组的数值。
输出描述:
输出一个整数,代表最终的二维数组中所有元素之和的最大值。
示例1
输入
3 3
1 2 3
1 2 3
输出
22

解题思路: 初始时, 为一个n*m的二维数组, 最多操作m+n次, 选中第i行, 该行所有元素变为ri, 选中第j列, 该列所有元素变为cj, 对于每个格子(i,j), 最终的值取决于最后一次覆盖它的操作, 如果最终是行覆盖就为ri, 列覆盖的话就为cj, 行/列的顺序是无所谓的, 对于每一行来说, 我们先用行覆盖, 如果列覆盖有更优的, 我们再用列覆盖进行调整, 代码实现上, 我们先对c数组进行排序,   在遍历r数组的同时, 去c数组中找到第一个>r[i]的数, 那么它左侧的元素就用ri(行覆盖), 右侧的数就用cj(列覆盖), (右侧是连续数组, 我们可以用前缀和进行统计), 单行的总和就为

k*r[i]+(prefix[m]-prefix[k])

可以有人会有疑问,那如果我在第一行我用列覆盖,那在考虑第二行的时候, 会不会受影响啊?

其实是不会的, 这就是我上面的提到的行/列顺序是没有顺序的, 第二行覆盖在第一行的列覆盖之前操作,就解决了这个问题 (这题有点硬控我啊)

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n, m;
    cin >> n >> m;
    vector<int> a(n), b(m);
    for(int i = 0; i < n; i++) cin >> a[i];
    for(int i = 0; i < m; i++) cin >> b[i];
    sort(b.begin(), b.end());
    vector<long long> prefix(m + 1, 0);
    for(int j = 0; j < m; j++){
        prefix[j + 1] = prefix[j] + b[j];
    }
    long long total_B = prefix[m];
    long long ans = 0;
    for(int i = 0; i < n; i++){
        int k = upper_bound(b.begin(), b.end(), a[i]) - b.begin();
        ans += (long long)k * a[i] + (total_B - prefix[k]);
    }
    cout << ans << endl;
    return 0;
}

 3. 树上替身追赶游戏

本题与《E.图上替身追赶游戏》共享部分题目背景,我们建议您重新阅读题面。

给定一棵由 n 个点和 n−1 条边组成的树,结点编号为 1∼n。Saki 和 Miku 在树上的点之间移动,模拟追赶游戏,初始时两个人都在节点 k。
游戏分若干回合进行,由你扮演 Saki。每回合包含以下步骤:
1.​Saki 移动:记回合开始时 Saki(你)在节点 a,你必须选择一个与 a 相邻的节点 b 并移动至 b;
2.​Saki 放置替身:Saki(你)不想被 Miku 追上,所以你必须选择一个与节点 b 相邻的节点 c 放置一个替身,该替身仅在本回合内存在;
3.​Miku 追赶:Miku 将替身视为 Saki 的位置并据此行动:
若 Miku 本就位于替身所在的节点 c,她停留不动;
否则,Miku 在其当前节点的相邻节点中,选择到节点 c 距离最近的节点 d 并移动到该节点(换句话说,点 d 是 Miku 所在的位置到点 c 的最短路径中的下一个节点)。
游戏在 Saki 首次移动后开始计为第 1 回合。如果在任何时刻 Saki 与 Miku 重合,游戏立即结束。
请计算,如果你采取最优策略,最多能够将游戏进行到第几回合?

输入描述:

第一行输入两个正整数 n,k(2≤n≤105; 1≤k≤n),表示树的结点数、双方起始位置。此后 n−1 行,第 iii 行输入两个整数 ui,vi(1≤ui,vi≤n),表示第 i 条树边连接第 ui 个点和第 vi​ 个点。保证给定的边构成一棵树。

输出描述:

输出一个整数,表示 Saki 最多能够坚持到第几回合结束。

示例1

输入

5 1

1 2

1 3

1 4

1 5
输出
2
在这个样例中,其中一种最优策略的移动状况如下:

1.​Saki 移动到 2 号结点;
2.​Saki 在 1 号结点放置替身;
3.​Miku 停留不动。
第二回合:
1.​Saki 移动到 1号结点。
此时,她与 Miku 重合,游戏结束。
我们可以证明,不存在比 2 回合坚持更久的策略。

解题思路: 看不懂题意的,可以直接看样例画个图, 求(重合)能坚持多少个回合

Saki 应该尽可能往远离 Miku 的方向跑,即往树的最深处跑
因为树的直径决定了 Saki 最多能跑多远

代码实现上:

计算 Miku 的最短距离(d_M):
从初始点 k 出发,BFS 计算 Miku 到所有节点的最短距离
计算 Saki 的最短距离(d_S):
Saki 每回合可以移动一步,但必须保证 d_S[u] + 1 <= d_M[v](即 Saki 不能跑到 Miku 已经能更快到达的地方)
最大回合数:
Saki 能跑的最远距离 max_d,回合数 = max_d + 1(因为第 max_d 步时 Miku 会追上)

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n, k;
    cin >> n >> k;
    vector<vector<int>> a(n+1);
    for(int i = 1, x, y; i < n; i++){
        cin >> x >> y;
        a[x].push_back(y);
        a[y].push_back(x);
    }
    vector<int> d_M(n+1, -1);
    queue<int> p;
    d_M[k] = 0;
    p.push(k);
    while(!p.empty()){
        int u = p.front(); p.pop();
        for(int v : a[u]){
            if(d_M[v] == -1){
                d_M[v] = d_M[u] + 1;
                p.push(v);
            }
        }
    }
    vector<int> d_S(n+1, -1);
    long long max_d = 0;
    queue<int> q;
    d_S[k] = 0;
    q.push(k);
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int v : a[u]){
            if(d_S[v] == -1 && d_S[u] + 1 <= d_M[v]){
                d_S[v] = d_S[u] + 1;
                max_d = max<long long>(max_d, d_S[v]);
                q.push(v);
            }
        }
    }
    cout << (max_d + 1) << endl;
    return 0;
}

4. 全对! 

题目链接:登录—专业IT笔试面试备考平台_牛客网

小 S 有 n 个对错机器人,每个对错机器人的行为逻辑由一个长度不超过 16,仅由字符 ‘0’ 和 ‘1’ 构成的字符串表示。在本题中,我们记字符串的下标从 1 开始。
对于第 i 个机器人,记其初始字符串为 si,其会先将这个字符串无限重复拼接成一个无限长的循环字符串 si∞​。随后,对于第 j 时刻,它会根据si∞​ 的第 j 个字符来决定回答「对的」还是「不对」:
∙ ,∙如果 si∞​ 的第 j 个字符为 ‘1’,则表示第 i 个机器人在第 j 秒回答「对的」;
∙,∙如果 si∞​ 的第 j 个字符为 ‘0’,则表示第 i 个机器人在第 j 秒回答「不对」。
更具体地,如果某个机器人的初始字符串是 "10101" ,那么这个机器人会在第 1,3,5,6,8,10,11,… 秒回答「对的」,在第 2,4,7,9,12,… 秒回答「不对」。
请问是否存在一个时刻 t,使得所有机器人在第 t 秒都回答「对的」,这样的时刻被称为「全对时刻」。如果存在,输出最小的「全对时刻」;否则,输出 −1。

解题思路:

举个例子:

3
001
0110
10001

3个字符串都是无限循环的, 

001001001001001...

0110011001100110....

100011000110001...

输出第一个全是1的时刻, 就是 6

往&运算上面思考(相同位置是1, '与'完仍然是1)即可, 模拟思路即可

代码实现上, 由于单个字符串(在不无限循环情况下)不会超过16,

对于每个长度为L的字符串,  我们需要记录每个位置r是否都为1, 

eg:

110

101

111

 b[0]=1, b[1]=0, b[2]=0

a[3][0]=1, a[3][1]=0, a[3][2]=0

a[L][r]: 表示长度为L的字符串在第r个位置是否全为1

接着枚举时间t , 需要找到最小额的t, 使得对于所有 L(1~16), t % L 对应的位置 r 满足 a[L][r] = true

eg: 解释一下这个% ,如果t=5, L=3, 5%3=2,检查a[3][2]是否为true, L=4, 5%4=1, 检查a[4][1]是否为 true, 如果所有L都满足, 那么t=5就是一个解, 没有解就输出-1。

#include <bits/stdc++.h>
using namespace std;
const int M = 1000000;
int main(){
    int n; cin>>n;
    vector<vector<bool>> a(17);
    for(int i=1;i<=16;i++){
        a[i].resize(i,true);
    }
    for(int i = 0; i < n; i++){
        string s;
        cin >> s;
        int L = s.size();
        vector<bool> b(L, false);
        for(int r = 0; r < L; r++){
            if(s[r] == '1')
            b[r] = true;
        }
        for(int r = 0; r<L;r++){
            a[L][r] = a[L][r] & b[r];
        }
    }
    for(int l = 1; l <= 16; l++){
        bool f = false;
        for(bool x : a[l]) if(x){ f = true; break; }
        if(!f){
            cout << -1 << endl;
            return 0;
        }
    }
    for(int t = 1; t <= M; t++){
        bool f = true;
        for(int l= 1; l<=16;l++){
            int r = (t-1)%l;
            if(!a[l][r]){
                f = false;
                break;
            }
        }
        if(f){
            cout << t << endl;
            return 0;
        }
    }
    cout << -1 << endl;
    return 0;
}

5. 图上替身追赶游戏 

为了甩开 Miku,你可以在游戏开始前发动一次「神之力」:在这棵树上选择不相邻的两个点 u,vu,随后在这两点之间加一条边,使得树变成一个无向图,随后,游戏在图上进行!特别地,这样操作后,如果 Miku 有多个满足条件的点选择,那么她一定会选择下标最小的那个并进行移动。
求解,有多少种不同的「神之力」施展方法,使得 Saki(你)可以在神之力发动后,通过一系列操作,在某个回合结束时,可以和 Miku 不相邻、不重合。

【注意】
与《C.树上替身追赶游戏》不同的是,在本题中,任何时刻 Saki 和 Miku 重合,游戏都不会结束。
在 u,v 加边和在 v,u加边被视为同一种「神之力」施展方法。更具体地,如果两次「神之力」选择的点相同,视为同一种加边方法。

输入描述:

第一行输入两个正整数 n,k(2≤n≤105; 1≤k≤n),表示树的结点数、双方起始位置。
此后 n−1 行,第 iii 行输入两个整数ui​,vi​(1≤ui​,vi​≤n),表示第 i 条树边连接第 ui 个点和第 vi个点。保证给定的边构成一棵树。
输出描述:
输出一个整数,表示有多少种不同的「神之力」施展方法。

 此题是第三题的修改版

解题思路:树形DP,比赛的时候看F题题目挺短的, 就直接写F题, 这题没看

可以通过手玩一下样例发现,树在加边后会产生一个环,这个环是saki甩开miku的关键。当环的长度分别为4、5、6时,均可以通过一系列操作,使得在某个回合结束时,与miku不再相邻或重合。

也就是说本题可以转化为,计算给定树中长度为3、4和5的简单路径的总数量。代码采用树形动态规划(Tree DP)的思想来解决。

核心思路:

我们通过深度优先搜索(DFS)遍历树,并在DFS的过程中计算和累积路径信息。关键在于定义DP状态以及如何合并子树信息。

其中变量 ans 最终累计了所有长度为3、4、5的简单路径的数量。通过一次DFS遍历,利用 f[d][u] 数组存储子树内距离信息。在回溯时(即子节点DFS结束后),它首先利用当前 f[j][u](代表“左侧分支”)和 f[k-j][v](代表“右侧分支”,其中 v 是刚处理完的子节点)来组合路径并更新 ans,然后才将 v 子树的信息整合进 f[][u],为后续的计算做准备。这种“先计算贡献,再合并信息”的顺序是树形DP中常见的处理方式,确保了每个路径只被计算一次且不会遗漏。

代码

1. DP状态定义:

f[k][u]:表示在以节点 u 为根的子树中,与节点 u 距离为 k 的节点有多少个。

2. DFS过程详解:

dfs(u, fa) 函数处理以 u 为当前节点,fa 为其父节点的情况。

初始化:

dep[u] = dep[fa] + 1:计算当前节点 u 的深度(根节点深度为1,其父节点0的深度为0)。
f[0][u] = 1:对于节点 u 本身,它与自身的距离为0。所以以 u 为根的子树中,与 u 距离为0的节点只有 u 自己,数量为1。
遍历子节点: 对于 u 的每个子节点 v(v != fa):

递归调用: dfs(v, u)。这会先计算完成以 v 为根的子树中所有的 f[][v] 值。

路径统计 (核心部分): 在从 dfs(v, u) 返回后,我们利用已经计算好的 f[][u](包含 u 自身以及 u 的 在 v 之前处理过的 其他子树的信息)和 f[][v](包含 v 的子树信息)来统计经过边 (u,v) 的路径。 我们关注的路径形态是 X - ... - u - v - ... - Y,其中:

X 是在 u 的子树中(但在 v 的子树之外,或者是 u 本身)的一个节点。
Y 是在 v 的子树中的一个节点。
路径 X - ... - u 的长度为 j。这样的 X 有 f[j][u] 个。
路径 v - ... - Y 的长度为 d。这样的 Y 有 f[d][v] 个。
那么,完整路径 X - ... - u - v - ... - Y 的长度为 j + 1 + d (1代表边 (u,v) 的长度)。
代码中的循环 k->(2, 5): 实际上是在枚举 j+d 的值。

当 k = 2时,我们统计 j+d = 2,总路径长度为 j+d+1 = 3。
当 k = 3时,我们统计 j+d = 3,总路径长度为 j+d+1 = 4。
当 k = 4时,我们统计 j+d = 4,总路径长度为 j+d+1 = 5。
内层循环 j->(0, k + 1): 枚举了路径 X - ... - u 的长度 j (即 d1)。

那么路径 v - ... - Y 的长度 d (即 d2) 就必须是 k-j。
此时,符合条件的路径数量为 f[j][u] * f[k-j][v]。将这个乘积累加到 ans。
注意:这里的 f[j][u] 尚未包含来自子树 v 的贡献,这正是我们想要的,因为它保证了路径的两个分支分别来自 u 的不同“方向”(一个方向是 v 子树,另一个方向是 u 的其他子树或 u 自身)。
更新 f[][u]: 在统计完以 v 为一支的路径后,需要将子树 v 的信息合并到 f[][u] 中,以便后续 u 的其他兄弟子树或者 u 的父节点使用。 j-> (0,5): f[j + 1][u] += f[j][v] 这条语句的含义是: 如果一个节点 Z 在子树 v 中,且与 v 的距离为 j(这样的节点有 f[j][v] 个),那么节点 Z 与 u 的距离就是 j+1。 所以,我们将 f[j][v] 的值累加到 f[j+1][u] 上。 j 从0到4,意味着 j+1 从1到5。这对应了 f 数组的维度。

DFS起始: dfs(1, 0) 从节点1开始DFS,假设节点0是节点1的虚拟父节点,其深度为0。

#include <bits/stdc++.h>
using namespace std;
int n, _;
vector<vector<int>> g;
vector<vector<long long>> f;
long long ans;
vector<int> dep;
void dfs(int u, int fa) {
    dep[u] = dep[fa] + 1;
    f[0][u] = 1;
    for (int v : g[u]) {
        if (v == fa) continue;
        dfs(v, u);
        for (int k = 2; k <= 4; ++k) {
            for (int j = 0; j <= k; ++j) {
                ans += f[j][u] * f[k - j][v];
            }
        }
        for (int j = 0; j < 5; ++j) {
            f[j + 1][u] += f[j][v];
        }
    }
}

int main() {
    cin >> n >> _;
    g.assign(n + 1, {});
    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    f.assign(6, vector<long long>(n + 1, 0));
    dep.assign(n + 1, 0);
    ans = 0;
    dfs(1, 0);
    cout << ans << endl;
    return 0;
}

 6.素数回路

给定偶数 n,构造一个由1∼n 这 n 个不同的整数构成环形数组 a,使得相邻两项的差均为奇素数。
奇素数是指除了 2 以外的素数,最小的四个奇素数是 3,5,7,11

输入描述:

每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≤T≤105) 代表数据组数,每组测试数据描述如下:
在一行上输入一个偶数 n(2≤n≤10^5)。
除此之外,保证单个测试文件的 n 之和不超过 2×10^5。
输出描述:
对于每一组测试数据,新起一行。如果不存在合法的环形数组,直接输出 −1。否则,输出 n个整数,表示构造的环形数组 a。
你需要保证数组 a 是一个由 1∼n1  这 n 个不同的整数组成的数组,下标从 0 开始,满足任取 0≤i<n,∣ai−a(i+1) mod n∣均为奇素数。

解题思路:输入n,ai→[1,n], 排列满足相邻差是一个奇素数(除了2的素数)

我们从1开始考虑,如果n是奇数,例如n=5, 满足题意的就是 1→4, 连不起,

...n=7,  满足题意的就为1 4 7 2  (从1开始,每次考虑3或者5),还是不行,

n=8,  满足题意的就为1 4 7 2 5 8 3 6

n=9, 1 → 4 → 7 → 2 → 5 → 8 → 3 → 6 → 9 → 1 最后一步不行

观察可以得出, ai=1, 加上一个奇素数,就会变成偶数, 再加上一个奇素数就会变成奇数, 如果n是奇数, 最后一步就会变成奇数, 奇数-奇数=偶数, 就回不到起始点了

接下来,我们先将奇素数预处理一下,存到o_p这个数组中, 接着我们找一个奇素数p,  使得 n - p 也是奇素数(这个是观察出来的, 比如, n=8, n=10, n=12, 自己推导一下)

找到符合条件的p后,

构造环形数组:

使用公式:(cur - 1 + p) % n + 1 (eg: n=8)

cur=1 → (1-1+3)%8+1=4 → (4-1+3)%8+1=7 → (7-1+3)%8+1=2 → (2-1+3)%8+1=5 → (5-1+3)%8+1=8 → (8-1+3)%8+1=3 → (3-1+3)%8+1=6 → (6-1+3)%8+1=1。

最终数组:[1,4,7,2,5,8,3,6]。

检查相邻差:

|1-4|=3,|4-7|=3,|7-2|=5,|2-5|=3,|5-8|=3,|8-3|=5,|3-6|=3,|6-1|=5。

所有差都是奇素数,构造成功。(依旧硬控....)

#include <bits/stdc++.h>
using namespace std;
const int N = 200000; 
int main(){
    vector<bool> is_prime(N+1, true);
    is_prime[0] = is_prime[1] = false;
    for(int i = 2; i*i <= N; i++){
        if(is_prime[i]){
            for(int j = i*i; j <= N; j += i){
                is_prime[j] = false;
            }
        }
    }
    vector<int> o_p;
    for(int i = 3; i <= N; i += 2){
        if(is_prime[i]) o_p.push_back(i);
    }
    int T;
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        if(n < 8 || n % 2 != 0){
            cout << -1 << endl;
            continue;
        }
        int p = -1;
        for(int x : o_p){
            if(x >= n) break;
            int y = n - x;
            if(y >= 3 && is_prime[y]){
                p = x;
                break;
            }
        } 
        if(p == -1){
            cout << -1 << endl;
            continue;
        }
        vector<int> ans;
        int cur = 1;
        for(int i = 0; i < n; i++){
            ans.push_back(cur);
            cur = (cur - 1 + p) % n + 1;
        }
        cout << ans[0];
        for(int i = 1; i < n; i++) cout << ' ' << ans[i];
        cout << endl;
    }
    return 0;
}

7.k人训练方阵

吹奏部有 n 名部员,saki 作为吹奏部的一员,负责从 n 名部员中选择若干名部员组成「k 人方阵」来参加活动。这是指一个由吹奏部部员组成的表演方阵,首先必须有一个领队站在前面,方阵有若干排(可以 0排),但每排必须是 k 个人。 
请你帮 Saki 计算一下有多少种不同的「k 人方阵」选法?由于答案可能很大,请将答案对 (109+7) 取模后输出。
注意 saki 只要选出若干名部员,能够组成「k 人方阵」就可以了,不需要去安排每个人的分工和站的位置,对是否是领队不作区分。 

解题思路:组合数(快结束的时候, 套了一下板子, 超时了...)

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
const int MAXN = 1e7;
vector<long long> F, INV_fac;
int quPow(long long a, int n) {
    long long res = 1;
    while(n) {
        if(n & 1) res = res * a % MOD;
        a = a * a % MOD;
        n >>= 1;
    }
    return res;
}
void init(int MAXN) {
    F.resize(MAXN + 1,0);
    INV_fac.resize(MAXN + 1,0);
    F[0] = 1;
    for(int i = 1; i <= MAXN; i++)
        F[i] = F[i - 1] * i % MOD;
    INV_fac[MAXN] = quPow(F[MAXN], MOD - 2);
    for(int i = MAXN - 1; i >= 0; i--)
        INV_fac[i] = INV_fac[i + 1] * (i + 1) % MOD;
}
long long C(int n, int r) {
    if(r < 0 || r > n) return 0;
    return F[n] * INV_fac[r] % MOD * INV_fac[n - r] % MOD;
}
int main() {
    init(MAXN); 
    int T;
    cin >> T;
    while(T--) {
        int n, k;
        cin >> n >> k;
        long long ans = 0;
        for(int r = 1; r <= n; r += k) {
            ans = (ans + C(n, r)) % MOD;
        }
        cout << ans << endl;
    }
    return 0;
}

感谢大家的点赞和关注,你们的支持是我创作的动力!(其他细节,有时间再补充...)

FFmpeg + Qt 实现摄像头采集与 MP3 背景音乐 RTSP 推流 在直播或视频监控场景中,我们经常需要将摄像头画面与背景音乐混合后推送到 RTSP 服务器。本文将详细介绍如何使用Qt框架结合摄像头实时采集(Windows 下使用dshow,Linux 使用v4l2视频预览(显示为 QImage)视频 H.264 编码 + RTSP 推流从 MP3 文件读取音频,重采样为 AAC 编码并推流循环播放音频文件解决中文文件路径打开失败的问题文章将剖析每个技术环节的关键代码,并给出完整的类实现。 阅读详情

相关推荐

退火朗之万动力学采样

退火朗之万动力学采样(Simulated Annealing Langevin Dynamics Sampling)结合了退火技术和朗之万动力学,是一种用于分子模拟和统计物理中的计算方法。这种方法可以帮助系统从局部最小值中逃逸,以找到全局最小值或进行有效的配置空间探索。

weixin_39699362的博客 1947

牛客练习赛138-题解

出发的最长路径长度。因为每回合Saki必须移动,且Miku会向替身位置移动,最优策略是Saki沿着最长路径移动。我们需要确定行覆盖和列覆盖的最优顺序,使得最终矩阵和最大。关键在于理解后覆盖的操作会覆盖之前操作的值。找到通过人数最多的题目作为签到题。如果有多个,输出字母顺序最小的那个。次操作(每次选择一行或一列覆盖)使得最终矩阵元素和最大。游戏在两者重合时结束。求 Saki 最多能进行多少回合。Saki 和 Miku 初始都在节点。条边组成的树,节点编号为。题目本质是求在树上,从起点。

hongjianMa的博客 944

电力电子新手必看:COT控制模式的工作原理与典型应用场景解析

本文深入解析了COT控制模式的工作原理及其在电力电子领域的典型应用。COT控制(恒定导通时间控制)通过固定导通时间机制,解决了传统滞环控制的问题,特别适用于需要快速瞬态响应和高效率的应用场景,如CPU/GPU供电和便携设备电源管理。文章详细介绍了COT控制的核心流程、技术特点及设计实践中的关键考量,帮助电力电子新手快速掌握这一技术。

weixin_30745553的博客 520

牛客练习赛138

这道题看着很麻烦,仔细观察样例,虽然是分数形式,但并没有约分,分子就是真正的通过人数,题目就是让求通过人数最多的,并且样例因为是直接输出了通过人数最多的,因此我们直接求就ok。

2402_87610050的博客 1060

【SeedLab】Packet Sniffing and Spoofing Lab

本节实验要求:借助Scapy库,实现网络流量的捕获与伪造。

cold_windx的博客 4515

Android日志实战——车机日志获取(十五)

这个项目中的 Log 管理系统,其实只是将系统原生 Log 进行输出并导出,并没有太复杂的操作。还有一种 Log 管理系统需要对 Android 原生 Log 系统进行重写,例如我们使用 Log.d(tag, msg) 打印 Log,需要我们根据 tag 信息将不同模块的 Log 数据写入不同的本地文件下,这样可以方便不同模块查看自己的 Log,追踪异常问题。

小旭的专栏 3773

【每日一题】【前缀和优化】【前/后缀最值】牛客练习赛139 B/C题 大卫的密码 (Hard Version) C++

【每日一题】【前缀和优化】【前/后缀最值】牛客练习赛139 B/C题 大卫的密码 (Hard Version) C++

weixin_72899100的博客 887

Scale-up,scale-out技术概述

本文系统分析了Scale-up与Scale-out两种扩展技术在现代计算中的应用与发展。Scale-up通过增强单节点性能,适用于高耦合任务,而Scale-out通过横向扩展节点,实现高可用性和无限扩展。在芯片层面,Chiplet技术推动Scale-up发展;在数据中心层面,二者协同工作构建强大集群。光模块在长距离高带宽传输中发挥关键作用。文章对比了NVIDIA、AMD和Broadcom三家公司的技术路线,指出NVIDIA采用封闭生态,AMD选择开放标准,Broadcom则主导底层连接技术。未来发展方向将聚

元直的博客 1445

牛客周赛Round138

【代码】牛客周赛Round138。

2601_95527011的博客 162

EPO: Hierarchical LLM Agents with Environment PreferenceOptimization

长期决策和规划任务依然是基于大型语言模型(LLM)的智能体面临的一大挑战(Valmeekam 等,2023;Liu 等,2023;Silver 等,2024)。这些任务需要智能体进行多步骤的规划,同时保持行为的一致性和目标导向,这对于通常被设计用于即时和局部预测的大型语言模型来说颇为困难。此外,针对具身智能体的大型语言模型微调面临的一个关键难题是大规模标注数据的需求(Reed 等,2022)。

qq_52053775的博客 142

如何让C++程序生成dump文件?生成dump文件的方式有哪些?如何使用Windbg分析dump文件?

本文详细介绍了如何让C++程序生成dump文件、生成dump文件的多种方式以及如何使用Windbg分析dump文件,并给出了对应的实战分析案例,有一定的实战参考价值。

dvlinker的技术专栏 5万+

【C++】牛客 ——NC138 矩阵最长递增路径

你需要在矩阵中找到一条最长路径,使这条路径上的元素是递增的。:通过DFS遍历矩阵的每个单元格,从每个单元格开始搜索最长的递增路径。数据范围:1≤𝑛,𝑚≤10001≤n,m≤1000,0≤𝑚𝑎𝑡𝑟𝑖𝑥[𝑖][𝑗]≤10000≤matrix[i][j]≤1000。1. 对于每个单元格,你可以往上,下,左,右四个方向移动。例如:当输入为[[1,2,3],[4,5,6],[7,8,9]]时,对应的输出为5,方向数组包括四个方向:上、下、左、右。,用于存储从每个单元格开始的最长递增路径长度。

一岁就可帅的博客 1179

Yolov8-pose关键点检测:训练准备篇 | 自己数据集从labelme标注到生成yolo格式的关键点数据

yolov8-pose关键点检测系列:从数据集标记到生成适合yolo的关键点格式

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 5872

2025.5.9

刚上来签到题有点懵,看到大佬们2分钟就有写完的,自己有点zhuo急,写的很复杂的方法,用字符串统计数量,一个一个遍历(不知道自己怎么想的,nt。),pow来求n次方,还在考虑浮点数的问题,后来发现duck不必。今天参加了牛客练习赛,感觉水平一般,ac了五道,最后两个由于太饿了想去吃饭,放弃思考了。加密解密的题,找到规律就可以了,注意输入有空格的字符串需要用getline输入。今天学的字符串,没有学多少东西,由于白天的忙碌。前两天做过类似的题,用map存储次数就可以了。

sjwusjwos的博客 185

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

牛客练习赛41 666RPG

链接:https://ac.nowcoder.com/acm/contest/373/B 来源:牛客网 题目描述 在欧美,“666”是个令人极其厌恶和忌讳的数,被称为“野兽数”。 相传,尼禄,这位历史上以暴君著称的古罗马皇帝,在一次罗马大火后,无端指控是基督徒焚烧了罗马,并对他们进行大肆镇压。尼禄死后,部分基督徒出于对尼禄的恐惧,相信他并没有死去,而且还会回到罗马来。圣经《新约·启示录》中...

YOONGI 296

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

牛客练习赛 41 B- 666RGB

在欧美,“666”是个令人极其厌恶和忌讳的数,被称为“野兽数”。 相传,尼禄,这位历史上以暴君著称的古罗马皇帝,在一次罗马大火后,无端指控是基督徒焚烧了罗马,并对他们进行大肆镇压。尼禄死后,部分基督徒出于对尼禄的恐惧,相信他并没有死去,而且还会回到罗马来。圣经《新约·启示录》中说,有一头野兽“因伤致死,但是它的致命伤又治好了”。“你所看见的兽先前有,如今没有,将要从无底坑里上来……可以计算野兽的数...

Wind_bow的博客 662

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

算法_python_牛客华为机试笔记_01

本文总结了华为机试题库(HJ1-HJ15)的解题思路与关键知识点。主要内容包括:1.字符串处理(分割、逆序、补零、统计字符);2.数学运算(进制转换、质数因子、近似值计算);3.数据结构应用(字典操作、列表去重与排序);4.位运算技巧(1的个数统计)。

AouSdu 1023

【数据结构】LeetCode160.相交链表 138.随即链表复制 牛客——链表回文问题

LeetCode 160 与138 题 牛客 OR36题

凤年徐的博客 2115

(动态规划)牛客练习赛41 B题

链接:https://ac.nowcoder.com/acm/contest/373/B 来源:牛客网 666RPG 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 32768K,其他语言65536K 64bit IO Format: %lld 题目描述 在欧美,“666”是个令人极其厌恶和忌讳的数,被称为“野兽数”。 相传,尼禄,这位历史上以暴君著称的古罗马皇帝,在一...

ACM5100的博客 642

矩阵最长递增路径 (记忆化的递归搜索,动态规划)

牛客NC138 矩阵最长递增路径 leetcode329 矩阵中的最长递增路径 记忆化的深度优先遍历 每个点的最长递增路径是确定,因此我们可以记录每个点的最长递增路径的长度,下一次访问到该点时就直接返回路径长度即可。 会不会出现路径重复的情况(如下图的情况)呢? 很明显是不会的,因为路径是递增的,这种情况会破坏路径的递增关系。 private int[][] dirs = new int[][]{{1, 0}, {0, -1}, {-1, 0}, {0, 1}}; private in

qq_44688635的博客 360

牛客练习赛41 b 666RPG (01背包)

时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 32768K,其他语言65536K 64bit IO Format: %lld 题目描述 在欧美,“666”是个令人极其厌恶和忌讳的数,被称为“野兽数”。 相传,尼禄,这位历史上以暴君著称的古罗马皇帝,在一次罗马大火后,无端指控是基督徒焚烧了罗马,并对他们进行大肆镇压。尼禄死后,部分基督徒出于对尼禄的恐惧,相信他并没有死去,而且...

caowenbo2311694605的博客 299

BC138 矩阵转置-C语言初学

KiKi有一个矩阵,他想知道转置后的矩阵(将矩阵的行列互换得到的新矩阵称为转置矩阵),请编程帮他解答。

kim的博客 176

【牛客】SQL138 连续两次作答试卷的最大时间窗-窗口函数

解释:用户1006分别在20210901、20210906、20210907作答过3次试卷,连续两次作答最大时间窗为6天(1号到6号),他1号到7号这7天里共做了3张试卷,平均每天3/7=0.428571张,那么6天里平均会做0.428571*6=2.57张试卷(保留两位小数);请计算在2021年至少有两天作答过试卷的人中,计算该年连续两次作答试卷的最大时间窗days_window,那么根据该年的历史规律他在days_window天里平均会做多少套试卷,按最大时间窗和平均做答试卷套数倒序排序。

talle2021的博客 1086

牛客SQL138——连续两次作答试卷的最大时间窗

思路:请计算在2021年至少有两天作答过试卷的人中,计算该年连续两次作答试卷的最大时间窗days_window,那么根据该年的历史规律他在days_window天里平均会做多少套试卷,按最大时间窗和平均做答试卷套数倒序排序。1.# 先找到在2021年至少做了两天试卷的人。2.计算时间窗,先找到连续第二次作答的时间。3.#计算最大时间窗,以及平均时间。

weixin_51350949的博客 198

C语言刷牛客竞赛语法入门——顺序结构

C语言刷牛客竞赛的新手语法入门

weixin_55511545的博客 2118

补题记录表3

pta SMU 2026 Spring 天梯赛7(补题):8,9,10。牛客周赛 Round 138 A,B,C,D,E。

Hikz1的博客 23
上一篇: 力扣第448场周赛
下一篇: 牛客周赛 Round 92(再现京津冀蓝桥杯???)
一只鱼^_
博客等级 码龄3年 1073粉丝 92原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值