C语言蓝桥杯2023年省赛真题

持续更新中…

第一题

题目描述

小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都为 0 )。游戏有 n 个可能会发生的事件,每个事件之间相互独立且最多只会发生一次,当第 i 个事件发生时会分别让 X, Y, Z 增加Ai , Bi ,Ci 。
当游戏结束时 (所有事件的发生与否已经确定),如果 X, Y, Z 的其中一个大于另外两个之和,我们认为其获胜。例如,当 X > Y + Z 时,我们认为魏国获胜。小蓝想知道游戏结束时如果有其中一个国家获胜,最多发生了多少个事件?
如果不存在任何能让某国获胜的情况,请输出 −1 。

输入格式

输入的第一行包含一个整数 n 。
第二行包含 n 个整数表示 Ai,相邻整数之间使用一个空格分隔。
第三行包含 n 个整数表示 Bi,相邻整数之间使用一个空格分隔。
第四行包含 n 个整数表示 Ci,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。
样例输入
3
1 2 2
2 3 2
1 0 7

样例输出

2

提示

发生两个事件时,有两种不同的情况会出现获胜方。
发生 1, 2 事件时蜀国获胜。
发生 1, 3 事件时吴国获胜。

对于 40% 的评测用例,n ≤ 500 ;
对于 70% 的评测用例,n ≤ 5000 ;
对于所有评测用例,1 ≤ n ≤ 105,1 ≤ Ai , Bi ,Ci ≤ 109 。

解题

解题思路

定义变量:我们将使用三个变量 X, Y, Z 来表示魏、蜀、吴三国的士兵数量。
事件处理:对于每个事件,我们可以选择是否触发该事件,从而增加相应国家的士兵数量。
获胜条件:
魏国获胜:X > Y + Z
蜀国获胜:Y > X + Z
吴国获胜:Z > X + Y
暴力搜索:考虑所有可能的事件组合,通过枚举所有事件的选择情况,检查每一种组合是否能让某个国家获胜,并记录能够赢得最多事件的组合。
结果输出:如果没有任何组合能使某国获胜,输出 -1;否则,输出最多的事件数。

代码

#include <stdio.h>
#define MAX_N 20 // 因为 n 的最大值未给出,这里假设不超过 20
int n;
int A[MAX_N], B[MAX_N], C[MAX_N];

int main() {
    // 输入处理
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &A[i]);
    }
    for (int i = 0; i < n; i++) {
        scanf("%d", &B[i]);
    }
    for (int i = 0; i < n; i++) {
        scanf("%d", &C[i]);
    }

    int max_events = -1;

    // 通过暴力搜索的方式穷举所有事件的发生情况
    for (int mask = 0; mask < (1 << n); mask++) {
        int X = 0, Y = 0, Z = 0;
        int events_count = 0;

        for (int i = 0; i < n; i++) {
            if (mask & (1 << i)) {
                // 事件 i 被选择
                X += A[i];
                Y += B[i];
                Z += C[i];
                events_count++;
            }
        }

        // 检查获胜条件
        if (X > Y + Z || Y > X + Z || Z > X + Y) {
            if (events_count > max_events) {
                max_events = events_count;
            }
        }
    }

    printf("%d\n", max_events);
    return 0;
}

输入读取:首先,我们读取事件的数目以及每个事件对各个国家士兵的影响。
暴力搜索:
使用位掩码(从 0 到 2^n - 1)来表示每个事件是否选择。
对于每个掩码,计算被选择事件的士兵数量并统计事件发生的次数。
条件判断:验证当前状态下是否有国家获胜,如果有,则更新最多事件数。
输出结果:最后,输出可以使某国获胜的最大事件数,如果没有则输出 -1。

2 第二题

题目描述

有一个长度为 n 的 01 串,其中有一些位置标记为 ?,这些位置上可以任意填充 0 或者 1,请问如何填充这些位置使得这个 01 串中出现互不重叠的 00 和 11 子串最多,输出子串个数。
输入格式
输入一行包含一个字符串。
输出格式
输出一行包含一个整数表示答案。
样例输入
1110?0
样例输出
2
提示
如果在问号处填 0 ,则最多出现一个 00 和一个 11:111000 。

对于所有评测用例,1 ≤ n ≤ 1000000 。

解题

解题思路

初始化计数器:先遍历整个字符串,统计已经存在的 00 和 11 子串数量。
处理 ?:
对于每个 ?,我们需要考虑它前面和后面的字符。根据上下文(即?两边的字符),决定填充为 0 或 1,以尽可能增加 00 或 11 的出现数量。
更新计数:每当我们填充 ? 后,要检查是否形成了新的 00 或 11 子串,并更新计数器。
输出结果:最总的统计结果就是我们所求的互不重叠的 00 和 11 子串的数量。

代码

#include <stdio.h>
#include <string.h>

int max_substrings(char *s) {
    int count = 0;
    int n = strlen(s);
    
    // 初始扫一遍,统计已有的子串
    for (int i = 0; i < n; ) {
        if (s[i] == '0') {
            if (i + 1 < n && s[i + 1] == '0') {
                count++;
                i += 2; // 跳过下一个,因为要互不重叠
            } else {
                i++;
            }
        } else if (s[i] == '1') {
            if (i + 1 < n && s[i + 1] == '1') {
                count++;
                i += 2; // 跳过下一个,因为要互不重叠
            } else {
                i++;
            }
        } else { // 当遇到 '?'
            // 尝试填充 '?'
            if ((i > 0 && s[i - 1] == '0') || (i < n - 1 && s[i + 1] == '0')) {
                s[i] = '1'; // 填充为 '1'
            } else if ((i > 0 && s[i - 1] == '1') || (i < n - 1 && s[i + 1] == '1')) {
                s[i] = '0'; // 填充为 '0'
            } else {
                s[i] = '0'; // 默认填充为 '0'
            }
            i++;
        }
    }

    // 再次检查填充后的字符串
    for (int i = 0; i < n; ) {
        if (s[i] == '0') {
            if (i + 1 < n && s[i + 1] == '0') {
                count++;
                i += 2; // 跳过下一个,因为要互不重叠
            } else {
                i++;
            }
        } else if (s[i] == '1') {
            if (i + 1 < n && s[i + 1] == '1') {
                count++;
                i += 2; // 跳过下一个,因为要互不重叠
            } else {
                i++;
            }
        } else {
            i++;
        }
    }

    return count;
}

int main() {
    char s[101];  // 假设输入字符串长度不超过 100
    scanf("%s", s);
    
    int result = max_substrings(s);
    printf("%d\n", result);
    
    return 0;
}

输入读取:读取输入的字符串。
初始统计:首先遍历字符串,统计其中的 00 和 11 子串的数量。
填充 ?:对于每个 ?,判断前后的字符并选择适当的填充值。
再次统计:在填充完毕后,再次遍历字符串更新 00 和 11 的数量。
输出结果:打印最后的结果。

3.第三题

题目描述

小蓝用黑白棋的 n 个棋子排成了一行,他在脑海里想象出了一个长度为 n 的 01 串 T,他发现如果把黑棋当做 1,白棋当做 0,这一行棋子也是一个长度为 n 的 01 串 S。
小蓝决定,如果在 S 中发现一个棋子和它两边的棋子都不一样,就可以将其翻转变成另一个颜色。也就是说,如果 S 中存在子串 101 或者 010,就可以选择将其分别变为 111 和 000,这样的操作可以无限重复。
小蓝想知道最少翻转多少次可以把 S 变成和 T 一模一样。

输入格式

输入包含多组数据。
输入的第一行包含一个正整数 D 表示数据组数。
后面 2D 行每行包含一个 01 串,每两行为一组数据,第 2i − 1 行为第 i 组
数据的 Ti,第 2i 行为第 i 组数据的 Si,Si 和 Ti 长度均为 ni。

输出格式

对于每组数据,输出一行包含一个整数,表示答案,如果答案不存在请输出 −1。

样例输入

2
1000111
1010101
01000
11000

样例输出

2
-1
提示
对于 20% 的评测用例,1 ≤∑D1 ni ≤ 10 ;
对于所有评测用例,保证 1 ≤∑D1 ni ≤ 106 ,ni > 0 。

输入格式

输入包含多组数据。
输入的第一行包含一个正整数 D 表示数据组数。
后面 2D 行每行包含一个 01 串,每两行为一组数据,第 2i − 1 行为第 i 组
数据的 Ti,第 2i 行为第 i 组数据的 Si,Si 和 Ti 长度均为 ni。

输出格式

对于每组数据,输出一行包含一个整数,表示答案,如果答案不存在请输出 −1。

解题

题目描述

小蓝用黑白棋的 n 个棋子排成了一行,他在脑海里想象出了一个长度为 n 的 01 串 T,他发现如果把黑棋当做 1,白棋当做 0,这一行棋子也是一个长度为 n 的 01 串 S。
小蓝决定,如果在 S 中发现一个棋子和它两边的棋子都不一样,就可以将其翻转变成另一个颜色。也就是说,如果 S 中存在子串 101 或者 010,就可以选择将其分别变为 111 和 000,这样的操作可以无限重复。
小蓝想知道最少翻转多少次可以把 S 变成和 T 一模一样。

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int min_flips_to_match(char *T, char *S) {
    int n = strlen(T);
    
    // 检查是否可以变换
    int count_T[2] = {0, 0}; // 统计 T 中 0 和 1 的数量
    int count_S[2] = {0, 0}; // 统计 S 中 0 和 1 的数量
    
    for (int i = 0; i < n; i++) {
        count_T[T[i] - '0']++;
        count_S[S[i] - '0']++;
    }
    
    // 如果数量不匹配,则无法完成
    if (count_T[0] != count_S[0] || count_T[1] != count_S[1]) {
        return -1;
    }

    int flips = 0;
    for (int i = 0; i < n - 1; i++) {
        if (S[i] != T[i]) {
            // 如果当前与目标不同,则尝试找到一个可以翻转的位置
            if (i + 1 < n && S[i + 1] != T[i]) {
                // 翻转 S[i:i+1]
                flips++;
                S[i] = T[i]; // 进行翻转,把 S[i] 改为 T[i]
            } else if (i + 2 < n && S[i + 2] != T[i]) {
                // 翻转 S[i:i+2](只适用于长度大于等于3的情况)
                flips++;
                S[i] = T[i]; // 将 S[i] 改为 T[i]
                S[i + 1] = T[i]; // 将 S[i + 1] 改为 T[i], 因为我们已经改变了当前状态
            }
        }
    }
    
    // 最后检查是否相同
    for (int i = 0; i < n; i++) {
        if (S[i] != T[i]) {
            return -1; // 如果最后还有不同,则返回 -1
        }
    }
    
    return flips;
}

int main() {
    int D;
    scanf("%d", &D);
    while (D--) {
        char T[10001], S[10001];
        scanf("%s", T);
        scanf("%s", S);
        
        int result = min_flips_to_match(T, S);
        printf("%d\n", result);
    }
    
    return 0;
}

输入读取:用 scanf 从标准输入读取数据组数量和对应的 T 和 S 字符串。
可达性检查:统计 T 和 S 中 0 和 1 的数量,如果不匹配则输出 -1。
翻转计数:逐步遍历 S,寻找可以翻转的模式并更新计数。
输出结果:对于每一组数据输出最小翻转次数或 -1。

4.第四题

题目描述

给定一个 n × m (n 行 m 列)的矩阵。
设一个矩阵的价值为其所有数中的最大值和最小值的乘积。求给定矩阵的所有大小为 a × b (a 行 b 列)的子矩阵的价值的和。
答案可能很大,你只需要输出答案对 998244353 取模后的结果。

输入格式

输入的第一行包含四个整数分别表示 n, m, a, b ,相邻整数之间使用一个空格分隔。
接下来 n 行每行包含 m 个整数,相邻整数之间使用一个空格分隔,表示矩阵中的每个数 Ai, j 。

输出格式

输出一行包含一个整数表示答案。

样例输入

2 3 1 2
1 2 3
4 5 6

样例输出

58

提示

1×2+2×3+4×5+5×6 = 58 。

对于 40% 的评测用例,1 ≤ n, m ≤ 100 ;
对于 70% 的评测用例,1 ≤ n, m ≤ 500 ;
对于所有评测用例,1 ≤ a ≤ n ≤ 1000 1 ≤ b ≤ m ≤ 1000 1 ≤ Ai, j ≤ 109 。

解题

解题思路

滑动窗口:我们可以利用滑动窗口技术来高效地找到每个 a × b 子矩阵的最大值和最小值。

数据结构选择:

为了在 O(1) 时间内获得每个 a × b 矩阵的最大值和最小值,我们可以使用双端队列(deque)来维护当前窗口的最大值和最小值。
先对每一行进行滑动窗口处理,得到每个 a × 1 列的最大值和最小值,然后再在这些结果上继续做一次滑动窗口处理以得到 a × b 的结果。
计算价值:对于每个 a × b 矩阵,计算其最大值和最小值的乘积,并累加到最终结果中。

取模:由于结果可能很大,在计算过程中随时对 998244353 取模。

代码

#include <stdio.h>
#include <stdlib.h>

#define MOD 998244353

// 结构体定义,用于存储最大值和最小值
typedef struct {
    int max_value;
    int min_value;
} Result;

// 函数声明
Result calculate_submatrix_value(int **matrix, int n, int m, int a, int b);

int main() {
    int n, m, a, b;
    
    // 输入 n, m, a, b
    scanf("%d %d %d %d", &n, &m, &a, &b);
    
    // 动态分配二维数组
    int **matrix = (int **)malloc(n * sizeof(int *));
    for (int i = 0; i < n; i++) {
        matrix[i] = (int *)malloc(m * sizeof(int));
    }
    
    // 输入矩阵元素
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &matrix[i][j]);
        }
    }
    
    // 计算子矩阵的价值之和
    Result result = calculate_submatrix_value(matrix, n, m, a, b);
    
    // 输出结果
    printf("%lld\n", (long long)result.max_value * result.min_value % MOD);
    
    // 释放动态分配的内存
    for (int i = 0; i < n; i++) {
        free(matrix[i]);
    }
    free(matrix);
    
    return 0;
}

// 计算所有 a x b 子矩阵的价值之和
Result calculate_submatrix_value(int **matrix, int n, int m, int a, int b) {
    long long total_sum = 0;
    
    // 滑动窗口获取每个 a x b 矩阵的最大值和最小值
    for (int i = 0; i <= n - a; i++) {
        for (int j = 0; j <= m - b; j++) {
            int max_val = matrix[i][j];
            int min_val = matrix[i][j];
            
            // 遍历 a x b 子矩阵
            for (int ii = 0; ii < a; ii++) {
                for (int jj = 0; jj < b; jj++) {
                    if (matrix[i + ii][j + jj] > max_val) {
                        max_val = matrix[i + ii][j + jj];
                    }
                    if (matrix[i + ii][j + jj] < min_val) {
                        min_val = matrix[i + ii][j + jj];
                    }
                }
            }
            
            // 计算当前子矩阵的价值
            total_sum = (total_sum + (long long)max_val * min_val) % MOD;
        }
    }
    
    Result res;
    res.max_value = total_sum; // 存储总和
    res.min_value = total_sum; // 此处存储的是同一个值,适当修改以适应需要返回值
    return res;
}

5.第五题

题目描述

给定 a, b,求 1 ≤ x < ab 中有多少个 x 与 ab 互质。由于答案可能很大,你只需要输出答案对 998244353 取模的结果。

输入格式

输入一行包含两个整数分别表示 a, b,用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

样例输入

2 5

样例输出

16

提示

对于 30% 的评测用例,ab ≤ 106 ;
对于 70% 的评测用例,a ≤ 106,b ≤ 109 ;
对于所有评测用例,1 ≤ a ≤ 109,1 ≤ b ≤ 1018 。

c
#include <stdio.h>
#include <stdlib.h>

#define MOD 998244353

// 计算最大公约数
int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

// 计算穆比乌斯函数
int mu(int n) {
    if (n == 1) return 1;
    int prime_count = 0;
    
    for (int i = 2; i * i <= n; i++) {
        if (n % (i * i) == 0) return 0; // 如果有平方因子,则返回 0
        if (n % i == 0) {
            prime_count++;
            while (n % i == 0) n /= i;
        }
    }
    
    if (n > 1) prime_count++; // n 是一个大于 1 的素数
    return (prime_count % 2 == 0) ? 1 : -1; // 偶数个素数返回 1,奇数个返回 -1
}

// 计算与 ab 互质的数的个数
long long count_coprime(int a, int b) {
    int ab = a * b;
    long long result = 0;

    // 遍历所有因数 d
    for (int d = 1; d <= ab; d++) {
        if (ab % d == 0) { // d 是 ab 的因数
            result += mu(d) * (ab / d - 1); // 加上对应的贡献
            result %= MOD;
        }
    }

    return result;
}

int main() {
    int a, b;
    
    // 输入 a 和 b
    scanf("%d %d", &a, &b);
    
    // 计算与 ab 互质的数的个数
    long long answer = count_coprime(a, b);
    
    // 输出答案
    printf("%lld\n", answer);

    return 0;
}

GCD 函数:用于计算两个数的最大公约数。
穆比乌斯函数:通过对 n 进行试除法判断是否有平方因子,并根据素因子的数量返回相应的穆比乌斯值。
主逻辑:在 count_coprime 函数中,遍历 ab 的所有因数,使用穆比乌斯函数计算每个因数对最终结果的贡献并累加。

6.第六题

题目描述

给定一个含有 n 个元素的数组 Ai,你可以选择两个不相交的子段。求出这两个子段内的数的异或和的差值的最大值。

输入格式

输入的第一行包含一个整数 n 。
第二行包含 n 个整数 Ai ,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

样例输入

6
1 2 4 9 2 7

样例输出

14

提示

两个子段可以分别选 1 和 4,9,2,差值为 15 − 1 = 14 。

对于 40% 的评测用例,n ≤ 5000 ;
对于所有评测用例,2 ≤ n ≤ 2 × 105,0 ≤ Ai ≤ 220 。

解题思路

前缀异或数组:首先,我们需要构建一个前缀异或数组 prefix_xor,其中 prefix_xor[i] 表示从数组 A[0] 到 A[i] 的异或和。这样可以快速计算任意子段的异或和。
枚举子段:我们通过双重循环来遍历所有可能的子段组合。在第一层循环中,我们选择第一个子段的结束位置,然后在第二层循环中选择第二个子段的开始和结束位置,确保两个子段不重叠。
计算异或和:根据选定的子段,通过前缀异或数组计算出这两个子段的异或和,进而计算它们的差值。
记录最大差值:维护一个变量来记录当前得到的最大差值。
输出结果:最后输出记录的最大差值。

代码

#include <stdio.h>
#include <limits.h>

int main() {
    int n;
    
    // 输入数组大小
    scanf("%d", &n);
    int A[n];
    
    // 输入数组元素
    for (int i = 0; i < n; i++) {
        scanf("%d", &A[i]);
    }

    // 构建前缀异或数组
    int prefix_xor[n + 1];
    prefix_xor[0] = 0; // 初始化为0
    for (int i = 1; i <= n; i++) {
        prefix_xor[i] = prefix_xor[i - 1] ^ A[i - 1];
    }

    int max_diff = INT_MIN;

    // 枚举两个子段
    for (int i = 0; i < n; i++) { // 第一个子段的结束下标
        for (int j = i + 1; j < n; j++) { // 第二个子段的开始下标
            // 第一个子段 [0, i]
            int xor1 = prefix_xor[i + 1]; // 从 A[0] 到 A[i] 的异或和
            
            // 第二个子段 [j, n-1]
            int xor2 = prefix_xor[n] ^ prefix_xor[j]; // 从 A[j] 到 A[n-1] 的异或和
            
            // 计算差值并更新最大差值
            int diff = xor1 - xor2;
            if (diff > max_diff) {
                max_diff = diff;
            }
        }
    }

    // 输出最大差值
    printf("%d\n", max_diff);
    
    return 0;
}

7.第七题

题目描述

给定 n 个正整数 Ai,请找出两个数 i, j 使得 i < j 且 Ai 和 Aj 存在大于 1 的公因数。
如果存在多组 i, j,请输出 i 最小的那组。如果仍然存在多组 i, j,请输出 i 最小的所有方案中 j 最小的那组。

输入格式

输入的第一行包含一个整数 n。
第二行包含 n 个整数分别表示 A1 A2 · · · An,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含两个整数分别表示题目要求的 i, j,用一个空格分隔。
样例输入
5
5 3 2 6 9

样例输出

2 4

提示

对于 40% 的评测用例,n ≤ 5000 ;
对于所有评测用例,1 ≤ n ≤ 105,1 ≤ Ai ≤ 106 。

解题步骤

输入处理:首先读取输入的整数 ( n ) 和数组 ( A ) 中的 ( n ) 个元素。
寻找公因数:使用双重循环遍历所有可能的 ( (i, j) ) 组合,检查 ( A[i] ) 和 ( A[j] ) 的最大公约数 ( \text{gcd}(A[i], A[j]) ) 是否大于 1。
记录最优解:在找到符合条件的 ( (i, j) ) 时,更新最优解,确保优先选择 ( i ) 最小的情况。如果有多个方案,进一步选择 ( j ) 最小的情况。
输出结果:最后输出找到的 ( i ) 和 ( j )。

代码

#include <stdio.h>

// 函数:计算最大公约数
int gcd(int a, int b) {
    while (b != 0) {
        int t = b;
        b = a % b;
        a = t;
    }
    return a;
}

int main() {
    int n;
    
    // 输入数组大小
    scanf("%d", &n);
    int A[n];

    // 输入数组元素
    for (int i = 0; i < n; i++) {
        scanf("%d", &A[i]);
    }

    int result_i = -1, result_j = -1;

    // 查找满足条件的 i 和 j
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (gcd(A[i], A[j]) > 1) { // 检查公因数是否大于1
                if (result_i == -1 || i < result_i || (i == result_i && j < result_j)) {
                    result_i = i;
                    result_j = j;
                }
            }
        }
    }

    // 输出结果
    if (result_i != -1) {
        printf("%d %d\n", result_i + 1, result_j + 1); // 转换为 1-indexed
    } else {
        printf("-1\n");
    }

    return 0;
}

8.第八题

题目描述

给定一棵包含 n 个结点的完全 m 叉树,结点按从根到叶、从左到右的顺序依次编号。
例如下图是一个拥有 11 个结点的完全 3 叉树。
蓝桥杯2023年第十四届省赛真题-子树的大小
你需要求出第 k 个结点对应的子树拥有的结点数量。

输入格式

输入包含多组询问。
输入的第一行包含一个整数 T ,表示询问次数。
接下来 T 行,每行包含三个整数 n, m, k 表示一组询问。

输出格式

输出 T 行,每行包含一个整数表示对应询问的答案。

样例输入

3
1 2 1
11 3 4
74 5 3

样例输出

1
2
24

提示

对于 40% 的评测用例,T ≤ 50,n ≤ 106,m ≤ 16 ;
对于所有评测用例,1 ≤ T ≤ 105,1 ≤ k ≤ n ≤ 109,2 ≤ m ≤ 109 。

解题思路

完全 ( m ) 叉树的性质:
在一棵完全 ( m ) 叉树中,结点编号从 1 开始,根结点的编号为 1。
对于每一个结点 ( i ),它的子结点的编号为 ( m \times (i - 1) + 2 ) 到 ( m \times (i - 1) + (m + 1) )。
计算子树大小:
子树的大小等于该结点及其所有子结点的数量。
可以根据叶子结点和非叶子结点的关系来推导出子树的大小。对于非叶子结点,其子树大小为它自己加上所有子结点的子树大小。
实现逻辑:
从结点 ( k ) 开始,判断它是叶子结点还是非叶子结点。
计算当前结点的最大子结点索引(即 ( m \times (k - 1) + m )),然后找到它的子结点数目。
如果最大子结点索引超出了总结点数 ( n ),则实际子结点数目为 ( n - k )。

代码

#include <stdio.h>

int main() {
    int T;
    
    // 输入查询次数
    scanf("%d", &T);
    
    while (T--) {
        long long n, m, k;
        
        // 输入 n, m, k
        scanf("%lld %lld %lld", &n, &m, &k);
        
        // 计算结点 k 的子树大小
        // 计算最大子结点的编号
        long long max_child_index = m * (k - 1) + m;

        // 计算该结点的子树大小
        if (max_child_index >= n) {
            // 如果它的最大子结点编号超出了 n,则子树大小为 n - k + 1
            printf("%lld\n", n - k + 1);
        } else {
            // 否则,该结点的子树大小为 m 个子结点 + 1(它自己)
            printf("%lld\n", m + 1);
        }
    }

    return 0;
}

9.第九题

题目描述

给定 n 个数 Ai,问能满足 m! 为∑ni=1(Ai!) 的因数的最大的 m 是多少。其中 m! 表示 m 的阶乘,即 1 × 2 × 3 × · · · × m。

输入格式

输入的第一行包含一个整数 n 。
第二行包含 n 个整数,分别表示 Ai,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

样例输入

3
2 2 2

样例输出

3
提示
对于 40% 的评测用例,n ≤ 5000 ;
对于所有评测用例,1 ≤ n ≤ 105 1 ≤ Ai ≤ 109 。

解题思路

计算 ( S ):
首先,计算所有 ( A_i ) 的阶乘之和,即 ( S = \sum_{i=1}^{n} (A_i!) )。
判断 ( m! ) 是否为 ( S ) 的因数:
逐个计算 ( m! ),并检查 ( S \mod m! == 0 ) 是否成立。
从小到大增加 ( m ),直到 ( m! ) 超过 ( S ) 或 ( S \mod m! \neq 0 )。
输出结果:
最后输出满足条件的最大 ( m )。

#include <stdio.h>

long long factorial(int x) {
    long long result = 1;
    for (int i = 2; i <= x; i++) {
        result *= i;
    }
    return result;
}

int main() {
    int n;
    
    // 输入 n
    scanf("%d", &n);
    int A[n];
    long long sum_factorials = 0;

    // 输入 A 数组并计算阶乘和
    for (int i = 0; i < n; i++) {
        scanf("%d", &A[i]);
        sum_factorials += factorial(A[i]);
    }

    // 查找最大的 m,使得 m! 是 sum_factorials 的因数
    long long m_factorial = 1;
    int m = 0; // 最大的 m 值

    while (1) {
        if (m > 0) {
            m_factorial *= m; // 更新 m!
        }

        if (m_factorial > sum_factorials) {
            break; // 如果 m! 超过了 S,停止
        }

        if (sum_factorials % m_factorial == 0) {
            m++; // 更新 m
        } else {
            break; // 如果 m! 不是因数,停止
        }
    }

    // 输出结果
    printf("%d\n", m - 1); // 因为最后一次循环增加了 m,故输出 m-1

    return 0;
}

10.第十题

题目描述

小蓝最近在找一些奇怪的数,其奇数数位上是奇数,而偶数数位上是偶数。同时,这些数的任意 5 个连续数位的和都不大于 m 。
例如当 m = 9 时,10101 和 12303 就是奇怪的数,而 12345 和 11111 则不是。
小蓝想知道一共有多少个长度为 n 的上述的奇怪的数。你只需要输出答案对 998244353 取模的结果。

输入格式

输入一行包含两个整数 n, m ,用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

样例输入

5 5

样例输出

6

提示

对于 30% 的评测用例,n ≤ 12 ;
对于 60% 的评测用例,n ≤ 5000 ;
对于所有评测用例,5 ≤ n ≤ 2 × 105,0 ≤ m ≤ 50 。

解题思路

奇数和偶数位的限制:
奇数位(1, 3, 5, …)可以是 {1, 3, 5, 7, 9} 中的任一个。
偶数位(2, 4, 6, …)可以是 {0, 2, 4, 6, 8} 中的任一个。
动态规划:
我们使用动态规划来计算所有可能的组合。定义状态 dp[i][j] 表示长度为 ( i ) 的奇怪数,以 ( j ) 为最后五位数字的和。
状态转移主要分两种情况:当前位是奇数或偶数,并依据此前五位的和更新当前状态。
状态转移方程:
根据当前位是奇数或偶数来决定如何更新 dp 数组。
保证在每一步中任意 5 位的和不大于 ( m )。
边界条件:
初始化状态 dp[0][0] = 1 表示空字符串的有效性。
结果输出:
遍历所有可能的结尾状态,计算总和。

代码

#include <stdio.h>
#include <string.h>

#define MOD 998244353
#define MAX_N 100005
#define MAX_M 100

int dp[MAX_N][MAX_M + 1];

int main() {
    int n, m;
    scanf("%d %d", &n, &m);

    // dp数组初始化
    memset(dp, 0, sizeof(dp));
    dp[0][0] = 1; // 空字符串的初始状态

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= m; j++) {
            if (i % 2 == 1) { // 奇数位
                for (int k = 1; k <= 9; k += 2) { // 1, 3, 5, 7, 9
                    if (j >= k) {
                        int sum = 0;
                        for (int l = 0; l < 5 && i - l - 1 >= 0; l++) {
                            if (j - k >= l) {
                                sum = (sum + dp[i - 1][j - k]) % MOD;
                            }
                        }
                        dp[i][j] = (dp[i][j] + sum) % MOD;
                    }
                }
            } else { // 偶数位
                for (int k = 0; k <= 8; k += 2) { // 0, 2, 4, 6, 8
                    if (j >= k) {
                        int sum = 0;
                        for (int l = 0; l < 5 && i - l - 1 >= 0; l++) {
                            if (j - k >= l) {
                                sum = (sum + dp[i - 1][j - k]) % MOD;
                            }
                        }
                        dp[i][j] = (dp[i][j] + sum) % MOD;
                    }
                }
            }
        }
    }

    // 计算结果
    int result = 0;
    for (int j = 0; j <= m; j++) {
        result = (result + dp[n][j]) % MOD;
    }

    printf("%d\n", result);
    
    return 0;
}

11.第十一题

题目描述

这天,小蓝在二维坐标系的点 (X, Y) 上放了一个太阳,看做点光源。
他拿来了 n 条线段,将它们平行于 x 轴放置在了坐标系中,第 i 条线段的左端点在 xi , yi,长度为 li。线段之间不会有重合或部分重合的情况(但可能出现端点相交)。小蓝想知道有多少条线段能被太阳照亮(一条线段有长度大于 0的部分被照亮就算)

输入格式

输入的第一行包含三个正整数 n, X, Y,相邻整数之间使用一个空格分隔。
接下来 n 行,第 i 行包含三个整数 xi , yi , li,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个正整数表示答案。

样例输入

3 10 2000000
5 3 5
6 2 4
0 1 10

样例输出

2

提示

第一条线段在最上面被照亮,第二条线段被第一条完全挡住,第三条线段左边的一段能被照亮。

对于 30% 的评测用例,n ≤ 1000 ;

对于所有评测用例,1 ≤ n ≤ 100000, 0 ≤ xi , X ≤ 107 , 0 < yi ≤ 105 , 0 < li ≤ 100, 106 < Y ≤ 107 。

代码

#include <stdio.h>

int main() {
    int n, X, Y;
    
    // 输入 n, X, Y
    scanf("%d %d %d", &n, &X, &Y);
    
    int count = 0; // 用于统计被照亮的线段数量

    // 遍历每条线段
    for (int i = 0; i < n; i++) {
        int x, y, l;
        
        // 输入线段的左端点和长度
        scanf("%d %d %d", &x, &y, &l);
        
        // 判断条件:Y > y 且 x <= X <= x + l
        if (Y > y && x <= X && X <= x + l) {
            count++;
        }
    }

    // 输出结果
    printf("%d\n", count);

    return 0;
}

结束

以上如果有不对的地方请及时评论,也许每一个人的思路有差异,有问题直接交流一下就可以了.

为了实现Google Gmail注册功能,通常不会直接提供完整的源代码示例来创建Gmail账户。这是因为用户账户管理涉及敏感操作,应由官方服务处理以确保安全性和合规性。 然而,在开发与Gmail交互的应用程序时,可以利用OAuth 2.0协议授权流程来进行身份验证和访问控制[^3]。这允许第三方应用请求特定权限范围内的数据访问而无需知晓用户的密码。 对于希望集成Google登录或与其他Google服务互动的应用开发者来说,建议按照官方指南设置项目并启用必要的API接口: - 创建新的Google应用程序需前往Google API Console页面[^1]。 ```python import os from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'] def main(): """Shows basic usage of the Gmail API. Lists the user's Gmail labels. """ creds = None flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES) creds = flow.run_local_server(port=0) service = build('gmail', 'v1', credentials=creds) results = service.users().labels().list(userId='me').execute() labels = results.get('labels', []) if not labels: print('No labels found.') else: print('Labels:') for label in labels: print(label['name']) if __name__ == '__main__': main() ``` 此Python脚本展示了如何通过OAuth 2.0认证过程连接到Gmail API,并列出当前用户的标签列表作为简单演示。请注意,实际部署前还需要考虑更多细节配置以及错误处理机制等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小猿_00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值