思路:阅读理解杯名不虚传。我们看到这一句:为了使答案为整数,因此按照秒输出,故得知题意得本意是如果当前休息完了开跑时体力不足,则选择跑到体力为0为止。也就是说我们应当认为在跑步过程中,每1s耗费10的体力。但是需要注意的是,本题还是有坑的,可能会有不少读者会想,完整的跑一次休息一次的效果是最终耗费300的体力,因此答案是10000/300个周期+剩余10000%300部分跑完。但是实际上这样是有问题的,我们只看最后10000%300=100,显然这个100是跑完休息后恢复到的状态,也就是说明跑之前的状态是100-300+400=200,但是200的体力明显不够我们跑完这一次,这样借体力是题目所不允许的需注意!!!!!
#include<bits/stdc++.h>
using namespace std;
int main(){
int energy = 10000, second = 0;
while(energy >= 600){
energy -= 300;
second += 120;
}
for(int i = 1 ;energy > 0 && i <= 60; ++ i) {
second += 1;
energy -= 10;
}
cout << second;
return 0;
}
思路:其实这题主要就是问从1921年7月23日到2020年7月1日一共有多少天x,结果就是x*24*60。考场上这种题目果断上Excel啊(雾)。这题时间设置的比较巧,如果两个日期都是1979年1月1日0时之后的,完全可以用库函数。因此如果非要用代码去写的话,就是蓝桥杯一贯喜欢考的平年闰年问题。
EXCEL做法:
1. 将单元格格式设置为日期格式
2. 输入数据
3. 利用公式求解,键入公式
于是EXCEL告诉我们一共有36138天,那么答案就是
编程做法:把日期前移到1921/7/23 0:00 ~ 2020 /7/1 0:00,单独算1921年和2020年的余下部分,累计上中间的年即可。
#include<bits/stdc++.h>
using namespace std;
int LeapYear[15] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, NoLeapYear[15] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool isLeap(int year){
return ( year % 4 == 0 && year % 100 != 0 ) || ( year % 400 == 0 );
}
int main(){
int i, LeapDays = 366, NoLeapDays = 365, ans = 9, year = 1921 ;
for(i = 1922 ; i < 2020; ++ i){
ans += isLeap(i) ? LeapDays : NoLeapDays;
}
for( i = 8; i <= 12 ; ++ i){
ans += isLeap(year) ? LeapYear[i]: NoLeapYear[i];
}
year = 2020;
for( i = 1 ; i < 7; ++ i ){
ans += isLeap(year) ? LeapYear[i] : NoLeapYear[i];
}
cout << ans * 24 * 60;
return 0;
}
思路:假设一共为100人,依据感染概率,只有1人被感染,于是根据基本不等式可知,使用的试剂数量为
k = 10时等号成立。
思路:手动计算未尝不可,编码则使用栈的方式+乘法原理,当然本题可以直接将循环代码写出,每有一层循环,相当于嵌套一层栈。直接分析该题,最外层A=A+9,执行一次,累加量为1*9=9,A=A+4和A=A+8执行两次,累加量为2*(4+8)=24,A=A+7执行10次,累加量为10*7=70,A=A+5执行60次,累加量为60*5=300。
#include<bits/stdc++.h>
using namespace std;
int main(){
int A = 0;
for(int i = 1; i <= 2; ++ i){
A = A + 4;
for(int j = 1; j <= 5; ++ j){
for(int k = 1; k <= 6; ++ k){
A = A + 5;
}
A = A + 7;
}
A = A + 8;
}
A = A + 9;
cout << A;
return 0;
}
首先可以明确的是,在这种条件下,[1,1]位置元素必为1,[2,2020]位置的元素必为2020。我们来探索一下剪枝优化DFS:
我们可以先安排第一行的,对于(1,j)位置的元素来说,要确保(1,j+1)~(1,1010)与(2,j)~(2,1010)这 个元素比他大,因此它的最大值只能是,最小值比左边元素大1;最小值很显然就是j了。
再安排第二行的,对于(2,j)位置的元素来说,要确保(2,j+1)~(2,1010)这个元素比他大,最大值只能是,最小值显然为2*j。
#include<bits/stdc++.h>
using namespace std;
int Num[2][2025], cnt;
bool used[2050];
void DFS(int row, int col, int pre){
if(row == 1 && col == 1010){
++ cnt;
return;
}
if(row == 0){
int Min = col, Max = 2 * col - 1;
for(int i = Min; i <= Max; ++ i){
if(!used[i]){
used[i] = true;
if(col == 1010)DFS(1, 1, 1);
else DFS(row, col + 1, i);
used[i] = false;
}
}
}
else if(row == 1){
int Min = 2 * col, Max = 1010 + col;
for(int i = Min; i <= Max; ++ i){
if(!used[i]){
used[i] = true;
DFS(row, col + 1, i);
used[i] = false;
}
}
}
}
我们来考虑优化:首先,当只有两个元素的时候,很显然,我们的数组只能按照如下方式填充:
当数组元素扩大到四个元素的时候,我们可以将3和4添加到后方,并且还有交换3与2的策略:
当数组元素扩大到6个元素的时候,我们可以将5和6添加到后方,并且还有交换5与4的策略:
(有待整理)
思路:大水题。。只需要注意数据范围开long long即可。
#include<bits/stdc++.h>
using namespace std;
int main(){
long long n;
cin >> n;
while( n ){
cout << n << " ";
n >>= 1;
}
return 0;
}
思路:阅读理解杯真不是盖的。按照本题原意,原来的字符串中只有英文字母,而小明又不会将超过9个的连续字母简写,因此在测试数据的输入中不应该会有两位整数及以上。说实话,个人觉得蓝桥杯这么搞真的没意思,到底考啥呢这是?起码给个样例说明一下,语塞。
不存在连续两位整数的情况:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str, res;
cin >> str;
int i, n = str.length();
char ch;
for( i = 0 ; i < n ; ){
if( isalpha(str[i]) ){ // 是字母
// 后一位是字母 那么当前字母只有一个 后一位不是字母 那么当前字母有不止一个
if( i + 1 < n && isdigit( str[i+1] ) ){
res += string(str[i+1] - '0', str[i]);
i += 2;
}else{
res += string(1, str[i]);
++ i;
}
}
}
cout << res;
return 0;
}
存在两位数及以上整数的情况:(考场上有机会还是写这种吧,万一他就是想坑你然后表述错了呢..-..)
#include<bits/stdc++.h>
using namespace std;
int main(){
string str, res;
int num;
cin >> str;
int i, n = str.length();
char ch;
for( i = 0 ; i < n ; ){
if( isalpha(str[i]) ){ // 是字母
// 后一位是字母 那么当前字母只有一个 后一位不是字母 那么当前字母有不止一个
if( i + 1 < n && isdigit( str[i+1] ) ){
num = 0;
ch = str[i];
++ i;
while( i < n && isdigit(str[i]) ){
num = num * 10 + str[i] - '0';
++ i;
}
res += string(num, ch);
}else{
res += string(1, str[i]);
++ i;
}
}
}
cout << res;
return 0;
}
思路:和走矩阵的动态规划题类似,注意双偶数坐标不要转移即可。
#include<bits/stdc++.h>
using namespace std;
int dp[40][40];
int main(){
int n, m, i, j;
cin >> n >> m;
dp[1][1] = 1;
for( i = 1 ; i <= n ; ++ i ){
for( j = 1 ; j <= m ; ++ j ){
if( i % 2 == 0 && j % 2 == 0 )continue;
if( i > 1 ) dp[i][j] += dp[i-1][j];
if( j > 1 ) dp[i][j] += dp[i][j-1];
}
}
cout << dp[n][m];
}
本菜一开始只想到了暴力算法。
https://blog.csdn.net/qq_43408978/article/details/108165611
看了这位大佬的博客之后,让我想起了两年前蓝桥杯的一道与和有关的题。题意大概是给出n个数和k,从这n个数中取出两个数,使得和为k,问一共有多少种方案。
我们来思考一下,到底意味着什么?是否意味着。也就是让我们找到在取模意义下的加法的补元。那么我们发现,当我们要求补元的时候,如果两个数模k的值相同,那么他们的补元是互通的。即设,补元为,由,得知如果存在,一定会有且。因此我们完全不需要考虑本身的值大小,只需要在取模操作下,把值映射到0~k-1,然后互补的元中取小的即可。
#include<bits/stdc++.h>
using namespace std;
const int MaxN = 100010;
int Arr[MaxN];
int main(){
int n, k, r, ans, i;
cin >> n;
for(i = 1 ; i <= n; ++ i){
cin >> r;
++ Arr[r%k];
}
ans = Arr[0] * (Arr[0] - 1) / 2 ;
if( k & 1 ){
for( i = 1; i <= ( k >> 1 ); ++ i ){
ans += min( Arr[i], Arr[k-i]);
}
}else{
ans += ( Arr[k>>1] >> 1 );
for( i = 1; i < (k >> 1); ++ i){
ans += min( Arr[i], Arr[k-i]);
}
}
cout << ans;
return 0;
}
现在我们来思考一下这一题,也是一个和为k倍数的问题,但是不是两个数直接相加,而是拼接。我们来看一下拼接后应该怎么思考这个问题,以12和345为例,假如我们要拼接出12345,实际上可以看成12000和345,于是只要12000和345互为模k意义下的补元。(等待补充)
由于每次从一台机器开始向外散布信息,我们可以把原先的n个点看作n个集合。(暂无思路)