蓝桥杯
- #A 双阶乘
- #B 格点
- 朴素解法
- 倍数法
- #C 整数分解
- 归纳法
- 数理分析
- #D 城邦
- #E 游戏
- #F 小平方
- #G 完全平方数
- #H 负载均衡
- #I 国际象棋
- 状压 DP
- #J 完美序列
- 动态规划
解析移步对应 Java组 的题解。
上课摸的鱼。
有无
#A 双阶乘
本题总分:
问题描述
的双阶乘用 表示。
例如:
。
。
。
请问, 的最后 位(这里指十进制位)是多少?
注意:。
提示:建议使用计算机编程解决问题。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
59375
#include <stdio.h>
int ans = 1, n = 2021, p = 100000;
int main() {
while (n > 0)
ans = ans * n % p, n -= 2;
printf("%05d", ans);
}
粪。
#B 格点
本题总分:
问题描述
的两维坐标都是整数,即 且 ,则称这个点为一个格点。
如果一个点 的两维坐标都是正数,即 且 ,则称这个点在第一象限。
请问在第一象限的格点中,有多少个点 的两维坐标乘积不超过 ,即 。
提示:建议使用计算机编程解决问题。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
15698
朴素解法
#include <stdio.h>
int ans = 0, n = 2021;
int main() {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i * j <= n) ans++;
printf("%d", ans);
}
倍数法
,生成其的二元组
的复杂度下计算出答案,这是因为不大于 的自然数的因数个数之和约等于
#include <stdio.h>
int ans = 0, n = 2021;
int main() {
for (int i = 1; i <= n; i++)
for (int j = 1; i * j <= n; j++) ans++;
printf("%d", ans);
}
#C 整数分解
本题总分:
问题描述
分解成两个正整数的和,有两种分解方法,分别是 和 。注意顺序不同算不同的方法。
将 分解成三个正整数的和,有 种分解方法,它们是 。
请问,将
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
691677274345
归纳法
,,设 划分 个的方案数为 ,
个正整数的方案为一,即 ;
个正整数的方案,有 种,即 ,,;
个正整数的方案,有 种,即 ,;
个正整数的方案,有 ,;
而且整理通项公式也容易出错,
我的建议是直接暴力累加。
#include <stdio.h>
long long ans = 0, n = 2021;
int main() {
for (int i = 3; i <= n - 2; i++)
ans += (i - 1) * (i - 2) * (n - i - 1) / 2;
printf("%lld", ans);
}
数理分析
看做 个 累加的结果,即 ,将每个 视作一个间隙,则间隙共有 个,对于每一种划分,我们都可以表示成任选四个间隙,然后先对间隙外的
比如:
时,这样的划分有
不能说跟概率毫不相干,
所以标题起了这个。
#include <stdio.h>
long long C(int n, int m) {
long long C = 1;
for (int i = 0; i < m; i++)
C = C * (n - i) / (i + 1);
return C;
}
int main() {
printf("%lld", C(2021 - 1, 4));
}
#D 城邦
本题总分:
问题描述
个城邦,依次编号 到 。在任意两个城邦之间,都有一座桥直接连接。
为了庆祝小蓝国的传统节日,小蓝国政府准备将一部分桥装饰起来。对于编号为 和 的两个城邦,它们之间的桥如果要装饰起来,需要的费用如下计算:找到 和 在十进制下所有不同的数位,将数位上的数字求和。
例如,编号为 和 两个城邦之间,千位、百位和个位都不同,将这些数位上的数字加起来是 。注意 没有千位,千位看成 。
为了节约开支,小蓝国政府准备只装饰 座桥,并且要保证从任意一个城邦到任意另一个城邦之间可以完全只通过装饰的桥到达。
请问,小蓝国政府至少要花多少费用才能完成装饰。
提示:建议使用计算机编程解决问题。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
4046
#include <stdio.h>
#include <string.h>
const int n = 2021;
int d[n + 1], v[n + 1], ans;
int min(int a, int b) { return a < b ? a : b; }
int calc(int a, int b) { return a == b ? 0 : a + b; }
int dist(int x, int y) { return calc(x / 1000, y / 1000) + calc(x / 100 % 10, y / 100 % 10) + calc(x / 10 % 10, y / 10 % 10) + calc(x % 10, y % 10); }
int main() {
memset(d, 0x3F, sizeof d);
d[1] = 0;
for (int i = 1; i < n; i++) {
int x = 0;
for (int j = 1; j <= n; j++)
if (!v[j] && (!x || d[j] < d[x])) x = j;
v[x] = 1;
for (int y = 1; y <= n; y++)
if (!v[y]) d[y] = min(d[y], dist(x, y));
}
for (int i = 1; i <= n; i++) ans += d[i];
printf("%d", ans);
}
。
#E 游戏
本题总分:
问题描述
小蓝闲着无聊开始自己和自己做游戏。
首先规定一个正整数 。
他首先在纸上写下一个 到 之间的数。在之后的每一步,小蓝都可以选择上次写的数的一个约数(不能选上一个写过的数),写在纸上。直到最终小蓝写下 。
小蓝可能有多种游戏的方案。
例如,当 时,小蓝有 种方案:, , , , , , , , 。
请问,当
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
1352184317599
#include <stdio.h>
const int n = 20210509;
long long ans, dp[n + 1] = {0, 1};
int main() {
for (int i = 1; i <= n; ans += dp[i++])
for (int j = i << 1; j <= n; j += i) dp[j] += dp[i];
printf("%lld", ans);
}
为以 开始的游戏方案数,显然答案为 ,,。
#F 小平方
时间限制: 内存限制: 本题总分:
问题描述
和一个小于 的正整数 ,将 平方后对 取余可能小于 的一半,也可能大于等于 的一半。
请问,在 到 中,有多少个数平方后除以 的余数小于 的一半。
例如,当 时, 的平方除以 的余数都小于 的一半。
又如,当 时, 的平方除以 的余数都是 ,小于 的一半。而 的平方除以 的余数都是 ,大于等于
输入格式
。
输出格式
输出一个整数,表示满足条件的数的数量。
测试样例1
Input:
5
Output:
2
评测用例规模与约定
。
#include <stdio.h>
int n, ans;
int main() {
scanf("%d", &n);
for (int i = 1; i < n; ++i)
if (i * i % n < n + 1 >> 1) ans++;
printf("%d", ans);
}
#G 完全平方数
时间限制: 内存限制: 本题总分:
问题描述
是一个完全平方数,是指它是某一个整数的平方,即存在一个整数 ,使得 。
给定一个正整数 ,请找到最小的正整数 ,使得它们的乘积是一个完全平方数。
输入格式
。
输出格式
。
测试样例1
Input:
12
Output:
3
测试样例2
Input:
15
Output:
15
评测用例规模与约定
% 的评测用例,,答案不超过 。
对于 % 的评测用例,,答案不超过 。
对于所有评测用例,,答案不超过 。
#include <stdio.h>
long long n, m, x = 1;
int main() {
scanf("%d", &n);
for (int i = 2; i <= n; ++i) {
for (m = 0; !(n % i); n /= i, m++);
if (m & 1) x *= i;
}
printf("%lld", x);
}
每届必考的算术基本定理。
,,
,满足 ,且
#H 负载均衡
时间限制: 内存限制: 本题总分:
问题描述
台计算机,第 台计算机的运算能力为 。
有一系列的任务被指派到各个计算机上,第 个任务在 时刻分配,指定计算机编号为 ,耗时为 且算力消耗为 。如果此任务成功分配,将立刻开始运行,期间持续占用 号计算机 的算力,持续 秒。
对于每次任务分配,如果计算机剩余的运算能力不足则输出 ,并取消这次分配,否则输出分配完这个任务后这台计算机的剩余运算能力。
输入格式
,分别表示计算机数目和要分配的任务数。
第二行包含 个整数 ,分别表示每个计算机的运算能力。
接下来 行每行 个整数 ,意义如上所述。数据保证 严格递增,即 。
输出格式
测试样例1
Input:
2 6
5 5
1 1 5 3
2 2 2 6
3 1 2 3
4 1 6 1
5 1 3 3
6 1 3 4
Output:
2
-1
-1
1
-1
0
Explanation:
时刻 1,第 1 个任务被分配到第 1 台计算机,耗时为 5 ,这个任务时刻 6 会结束,占用计算机 1 的算力 3。
时刻 2,第 2 个任务需要的算力不足,所以分配失败了。
时刻 3,第 1 个计算机仍然正在计算第 1 个任务,剩余算力不足 3,所以失败。
时刻 4,第 1 个计算机仍然正在计算第 1 个任务,但剩余算力足够,分配后剩余算力 1。
时刻 5,第 1 个计算机仍然正在计算第 1, 4 个任务,剩余算力不足 4,失败。
时刻 6,第 1 个计算机仍然正在计算第 4 个任务,剩余算力足够,且恰好用完。
评测用例规模与约定
% 的评测用例,。
对于 % 的评测用例,。
对于所有评测用例,,,。
#include <bits/stdc++.h>
using namespace std;
int V[200001];
priority_queue<pair<int, pair<int, int>>> pq;
int main() {
int n, m, a, b, c, d;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d", &a), V[i] = a;
pq.push(make_pair(-1000000009, make_pair(0, 0)));
while (~scanf("%d %d %d %d", &a, &b, &c, &d)) {
while (abs(pq.top().first) <= a)
V[pq.top().second.first] += pq.top().second.second, pq.pop();
if (V[b] >= d) {
pq.push(make_pair(-a - c, make_pair(b, d)));
printf("%d\n", V[b] -= d);
} else printf("-1\n");
}
}
优先列队模拟。
#I 国际象棋
时间限制: s 内存限制: MB 本题总分:
问题描述
个皇后,使得两两之间互不攻击的方案数。已经学习了很多算法的小蓝觉得 “八皇后” 问题太简单了,意犹未尽。作为一个国际象棋迷,他想研究在 的棋盘上,摆放 个马,使得两两之间互不攻击有多少种摆放方案。由于方案数可能很大,只需计算答案除以 (即 ) 的余数。
如下图所示,国际象棋中的马摆放在棋盘的方格内,走 “日” 字,位于 格的马(第 行第 列)可以攻击 、、、、、、 和 共
输入格式
,分别表示棋盘的行数、列数和马的个数。
输出格式
(即 ) 的余数。
测试样例1
Input:
1 2 1
Output:
2
测试样例2
Input:
4 4 3
Output:
276
测试样例3
Input:
3 20 12
Output:
914051446
评测用例规模与约定
% 的评测用例,;
对于另外 % 的评测用例,;
对于另外 % 的评测用例,;
对于另外 % 的评测用例,;
对于另外 % 的评测用例,;
对于所有评测用例,,,。
状压 DP
,表示已经摆放 至 列,其中第 列的摆放方案为 ,第 列的摆放方案为 ,且恰摆放了 个旗子时,合法的方案种数模
为一串 位二进制整数,第 为 表示在棋盘第 行 列摆有一个马,为
、、 两两不冲突, 为 中二进制位为
与 不冲突可表示为 和 的结果同为 ,即对于 上的每一个马,能攻击到 上的马,只在某两只马距离的绝对差为 时,值得注意的是, 可能会丢失 的信息,于是换为判断 。
与 同上,若 与 冲突,对于任意 、, 为 ,因此可以不用判断。
#include <stdio.h>
const int N = 6, M = 101, K = 20;
int n, m, k, dp[M][K][1 << N][1 << N] = {1}, ans, p = 1000000007;
int bitCount(int n) {
n = n - (n >> 1 & 0x55555555);
n = (n & 0x33333333) + (n >> 2 & 0x33333333);
n = n + (n >> 4) & 0x0F0F0F0F;
n = n + (n >> 8);
n = n + (n >> 16);
return n & 0x3F;
}
int main() {
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= m; ++i)
for (int now = 0; now < 1 << n; ++now)
for (int kk = bitCount(now); kk <= k; ++kk)
for (int pre1 = 0; pre1 < 1 << n; ++pre1)
if (!(now << 2 & pre1) && !(pre1 << 2 & now))
for (int pre2 = 0; pre2 < 1 << n; ++pre2)
if (!(now << 1 & pre2) && !(pre2 << 1 & now))
dp[i][kk][now][pre1] = (dp[i][kk][now][pre1] + dp[i - 1][kk - bitCount(now)][pre1][pre2]) % p;
for (int now = 0; now < 1 << n; ++now)
for (int pre = 0; pre < 1 << n; ++pre)
ans = (ans + dp[m][k][now][pre]) % p;
printf("%d", ans);
}
#J 完美序列
时间限制: s 内存限制: MB 本题总分:
问题描述
一个序列中取出一些元素按照原来的顺序排列成新的序列称为该序列的一个子序列。子序列的价值为子序列中所有元素的和。
如果一个序列是单调递减的,而且除了第一个数以外的任何一个数都是上一个数的因数,则称这个序列为一个完美序列。
一个序列中的一个子序列如果是完美序列,则称为该序列的一个完美子序列。一个序列的最长完美子序列长度,称为该序列的完美长度。
给定正整数 , 至 的所有排列的完美长度的最大值,称为 阶最大完美长度。
给定正整数 ,请求出 至 的所有排列中长度正好为
输入格式
每个评测用例包含多组询问。询问之间彼此独立。
输入的第一行包含一个整数 ,表示询问数。
接下来 行,每行包含一个整数 ,表示一个给定的 。
输出格式
行,依次对应每组询问的答案。
每行包含一个整数,表示对应的答案除以 (即 ) 的余数。
测试样例1
Input:
5
1
2
3
5
10
Output:
1
3
21
140
2268000
Explanation:
当 n = 1 时,答案显然是 1。
当 n = 2 时,全排列包括 (1, 2) 和 (2, 1),其中 (2, 1) 拥有最长的完美子序列,也就是 (2, 1) 本身,2 阶最大完美长度为 2,答案即为 2 + 1。
当 n = 3 时,全排列包括 (1, 2, 3)、(1, 3, 2)、(2, 1, 3)、(2, 3, 1)、(3, 1, 2)、(3, 2, 1)。其中 (2, 1) 和 (3, 1) 都是最长的完美子序列,3 阶最大完美长度为 2。
序列 (1, 2, 3) 和 (1, 3, 2) 中没有长度为 2 的完美子序列。
序列 (2, 1, 3) 中有完美子序列 (2, 1),价值和为 3。
序列 (2, 3, 1) 中有完美子序列 (2, 1) 和 (3, 1),价值和为 7。
序列 (3, 1, 2) 中有完美子序列 (3, 1),价值和为 4。
序列 (3, 2, 1) 中有完美子序列 (2, 1) 和 (3, 1),价值和为 7。
答案为 3 + 7 + 4 + 7 = 21。
评测用例规模与约定
% 的评测用例,;
对于 % 的评测用例,;
对于 % 的评测用例,,;
对于 % 的评测用例,,;
对于所有评测用例,,。
动态规划
、 为 、 这个量级,
,其中 以 为首的完美子序列的长度, 表示其个数,
,都可以转换为 上的求和,即 , 满足 ,即统计长度恰为 阶最大完美长度的所有完美子序列的价值的和,乘以 , 减 阶最大完美长度
,其中 为 , 中的最大值, 为 。
#include <stdio.h>
const int N = 1e6 + 1;
int T, n, dp[N + 1][3] = { 0, 0, 0, 1, 1, 1 }, sum[N + 1], start[N + 1], p = 1000000007;
long long pro[N + 1] = {0, 1}, inv[N + 1] = {0, 1}, buf[N + 1] = {0, 1};
int main() {
for (int i = 1; i <= N; i++) {
start[i] = dp[i][0] > dp[i - 1][0] ? i : start[i - 1];
sum[i] = (sum[i - 1] + (dp[start[i]][0] == dp[i][0] ? dp[i][1] : 0)) % p;
for (int j = i << 1; j <= N; j += i) {
if (dp[i][0] + 1 == dp[j][0]) {
dp[j][1] = (dp[j][1] + j + dp[i][1]) % p;
dp[j][2]++;
}
else if (dp[i][0] >= dp[j][0]) {
dp[j][1] = ((long long)j * dp[i][2] % p + dp[i][1]) % p;
dp[j][0] = dp[i][0] + 1;
dp[j][2] = dp[i][2];
}
}
}
for (int i = 2; i <= N; i++)
pro[i] = pro[i - 1] * i % p,
buf[i] = (p - p / i) * buf[p % i] % p,
inv[i] = inv[i - 1] * buf[i] % p;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
printf("%d\n", (sum[n] - sum[start[n] - 1] + p) % p * (pro[n] * inv[dp[start[n]][0]]) % p);
}
}
我的评价是,
不想出题可以不出。