2020蓝桥杯 C/C++ 省赛(7月)

å¨è¿éæå¥å¾çæè¿°

思路:阅读理解杯名不虚传。我们看到这一句:为了使答案为整数,因此按照秒输出,故得知题意得本意是如果当前休息完了开跑时体力不足,则选择跑到体力为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. 利用公式求解,键入公式C1=B1-A1

于是EXCEL告诉我们一共有36138天,那么答案就是36138*24*60=52038720

编程做法:把日期前移到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人被感染,于是根据基本不等式可知,使用的试剂数量为

                                                                                                                \frac{100}{k}+k>=20

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)这 1010-j+1010-j+1=2021- 2*j个元素比他大,因此它的最大值只能是2020-(2021-2*j) = 2*j-1,最小值比左边元素大1;最小值很显然就是j了。

再安排第二行的,对于(2,j)位置的元素来说,要确保(2,j+1)~(2,1010)这1010-j个元素比他大,最大值只能是2020-(1010-j)=1010+j,最小值显然为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,问一共有多少种方案。

我们来思考一下,\bg_white Arr[i]+Arr[j]=p*k到底意味着什么?是否意味着\bg_white Arr[i]+Arr[j]=0(mod\ k)。也就是让我们找到在取模意义下的加法的补元。那么我们发现,当我们要求补元的时候,如果两个数模k的值相同,那么他们的补元是互通的。即设x=m*k+r,补元为supple(x),由x+supple(x)=0(mod\ k),得知如果存在y=q*k+r,一定会有x=y(mod\ k)suppple(x)+y=0(mod\ 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个集合。(暂无思路)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值