🔔目录
蓝桥杯冲冲冲~
🔖蓝桥杯每日练习(猴子分香蕉,等差数列,平方序列,倍数问题)
🔖蓝桥杯每日练习(纯质数(筛法的应用),最少砝码,灌溉)
🔖蓝桥杯每日练习(年龄巧合,纸牌三角形,取球游戏)
🚶引言
今天继续蓝桥杯每日练习~ 今天的题目可以练习五个知识点 : dfs,优先队列,模拟,前缀和,二分。最近几天的练习题目几乎都有dfs,是因为它是一种很基础的搜索方式,因为它的难度一般不会太高所以在蓝桥杯省赛很喜欢考察。优先队列就是一个能把队列中元素排好顺序的队列。我是学习算法的小菜鸡,每天练习几个知识点,我们国赛见~
🚀今日题目
💓算式900
全排列 |
题目描述
(□□□□-□□□□)*□□=900
其中的小方块代表 0 ~ 9 的数字,这 10 个方块刚好包含了 0 ~ 9 中的所有数字。 注意:0 不能作为某个数字的首位。
小明经过几天的努力,终于做出了答案!如下:
(5012-4987)*36=900
用计算机搜索后,发现还有另外一个解,本题的任务就是:请你算出这另外的一个解。
注意:输出格式需要与示例严格一致; 括号及运算符号不要用中文输入法; 整个算式中不能包含空格。
解题报告
直接对十个数字全排列,然后按照题意把排列的结果分成三个数字,根据题意判断就可以了。
参考代码(C++版本)
#include<iostream>
using namespace std;
const int N = 11;
int st[N], res[N];
int idx;
int calc(int l, int r) {
int num = 0;
for (int i = l; i <= r; i++) {
num = num * 10 + res[i];
}
return num;
}
void dfs(int k) {
if (k == 10) {
int a = calc(0, 3);
int b = calc(4, 7);
int c = calc(8, 9);
if ((a - b) * c == 900 && a != 5012) {
printf("(%d-%d)*%d=900", a, b, c);
exit(0);
}
return;
}
for (int i = 0; i < 10; i++) {
if (!st[i]) {
st[i] = 1;
res[idx++] = i;
dfs(k + 1);
idx--;
st[i] = 0;
}
}
}
int main() {
dfs(0);
return 0;
}
🌟谈判
🌱题目描述
在很久很久以前,有 n 个部落居住在平原上,依次编号为 1 到 n。第 i 个部落的人数为 t[i]。
有一年发生了灾荒。年轻的政治家小蓝想要说服所有部落一同应对灾荒,他能通过谈判来说服部落进行联合。
每次谈判,小蓝只能邀请两个部落参加,花费的金币数量为两个部落的人数之和,谈判的效果是两个部落联合成一个部落(人数为原来两个部落的人数之和)。
原题传送门
优先队列 |
🌴解题报告
每次选择两个部落,但是他没有说两个部落的关系也就是说我们可以任意的选择。然后我们发现越是留到合并的部落被累加的次数越少,所以就要让大的部落往后放一放,先加规模小的部落。注意到他是一个合并的过程,所以每次拿出来两个部落后就会把他们的和放到队列中。然后因为有排序,我们就很自然的想到了优先队列。
然后顺带提一句为什么优先队列排序比每次做完排一下序快,优先队列其实是一个堆,一颗二叉树,他每次放进或者移出一个元素后的排序都是叶子之间的交换。
🌵参考代码(C++版本)
#include<iostream>
#include<queue>
using namespace std;
int n, a, ans;
priority_queue<int, vector<int>, greater<int>>q;
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a;
q.push(a);
}
while (q.size() != 1) {
int x = q.top(); q.pop();
int y = q.top(); q.pop();
ans += x + y;
q.push(x + y);
}
cout << ans << endl;
}
幸运数
题目描述
幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的"筛法"生成。
首先从 1 开始写出自然数 1,2,3,4,5,6,⋯
1 就是第一个幸运数。
我们从 2 这个数开始。把所有序号能被 2 整除的项删除,变为:
1 3 5 7 9⋯
把它们缩紧,重新记序,为:
13579⋯
这时,3 为第 2个幸运数,然后把所有能被 3 整除的序号位置的数删去。注意,是序号位置,不是那个数本身能否被 3 整除!!删除的应该是 5,11, 17…
此时 7 为第 3 个幸运数,然后再删去序号位置能被 7 整除的( 19,39…)
最后剩下的序列类似:
1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, ⋯
模拟 |
🚗解题报告
找规律然后发现找不到,于是就模拟。打一张状态表,然后就模拟题意。
参考代码(C++版本)
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int st[N];
int n, m;
int main() {
cin >> n >> m;
for (int i = 2; i <= m; i++) {
if (!st[i]) {
int cnt = 0;
for (int j = 1; j <= m; j++) {
if (!st[j]) {
cnt++;
if (cnt % i == 0) st[j]=1;
}
}
}
}
int ans = 0;
for (int i = n + 1; i < m; i++) if (!st[i]) ans++;
cout << ans << endl;
}
🙵123
题目描述
小蓝发现了一个有趣的数列,这个数列的前几项如下:
1, 1, 2, 1, 2, 3, 1, 2, 3, 4, ⋯
小蓝发现,这个数列前 1 项是整数 1,接下来 2 项是整数 1 至 2,接下来 3 项是整数 1 至 3,接下来 4 项是整数 1 至 4,依次类推。
小蓝想知道,这个数列中,连续一段的和是多少。
二分与前缀和 |
一中午wa吐了结果发现是数组开小了
🚇解题报告
首先因为他问的是区间和,我们自然而然地想到了这道题要用到前缀和。然后预处理前缀和的时候我们又发现每一段的和是从一开始的一段连续区间,我们又发现这个和用公式很好求,于是我们就稍微修改一下改为把每一段当作一个元素然后预处理他们的前缀和。求的是候我们发现要找小于等于所求数的最大的元素的位置,于是我们又可以想到二分。
参考代码(C++版本)
#include<iostream>
#define int long long
using namespace std;
const int N = 1e7 + 10;
int n, m, flag;
int num[N];
void init() {
for (int i = 1; i < N; i++) {
int res = i * (i + 1) / 2;
num[i] = res, num[i] += num[i - 1];
flag++;
if (res > 1e12) return;
}
return;
}
int calc(int k) {
if (k == 0) return 0;
int l = 0, r = flag;
while (l < r) {
int mid = l + r + 1 >> 1;
if (mid * (mid + 1) / 2 <= k) l = mid;
else r = mid - 1;
}
int ans = num[l];
int v = k - l * (l + 1) / 2;
ans += v * (v + 1) / 2;
return ans;
}
void solve() {
cin >> n >> m;
cout << calc(m) - calc(n - 1) << endl;
}
signed main() {
init();
int t;
cin >> t;
while (t--) {
solve();
}
}