2020第十一届蓝桥杯七月赛C/C++B组

Source

1:跑步训练

【问题描述】
小明要做一个跑步训练。
初始时,小明充满体力,体力值计为 10000。如果小明跑步,每分钟损耗
600 的体力。如果小明休息,每分钟增加 300 的体力。体力的损耗和增加都是
均匀变化的。
小明打算跑一分钟、休息一分钟、再跑一分钟、再休息一分钟……如此循
环。如果某个时刻小明的体力到达 0,他就停止锻炼。
请问小明在多久后停止锻炼。为了使答案为整数,请以秒为单位输出答案。
答案中只填写数,不填写单位。
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个
整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

#include <iostream>
#include <algorithm>
#include <vector> 
#define ll long long
using namespace std;

int main() {
    
      
	double t = 0;
	int t1 = 10000;
	while(t1 > 0){
    
      
		t++;
		if((int)t % 2 == 1){
    
      
			if(t1 - 600 < 0) break;
			else t1 -= 600;
		}
		else t1 += 300;
		//cout << t1 << endl;
	}
	//cout << t1 << endl;
	double s;
	if(t1){
    
      
		s = t1*1.0/10;
		t--;
	}
	cout << t*60 + s << endl;
	return 0;
}

答案:3880

2:纪念日

【问题描述】
2020 年 7 月 1 日是…。
…成立于 1921 年 7 月 23 日。
请问从 1921 年 7 月 23 日中午 12 时到 2020 年 7 月 1 日中午 12 时一共包含多少分钟?
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <vector> 
#define ll long long

using namespace std;

bool judge(int x)
{
    
      
	if((x % 4 == 0 && x % 100 != 0) || (x % 400 == 0)) return true;
	return  false;
}

int main()
{
    
      
	int sum = 0;
	for(int i = 1922; i <= 2019; i++){
    
      
		if(judge(i)){
    
      
			sum += 366;
		}
		else sum += 365;
	}
	int k = 334 + 9 + 1;
	sum = sum * 24 * 60;
	k = k * 24 * 60;
	cout << sum + k;
	return 0;
}

答案: 52038720

3:合并检测

【问题描述】
…由…引起,最近在 A 国蔓延,为了尽快控制…, A 国准备给大量民众进行…。
然而,用于检测的…紧缺。
为了解决这一困难,科学家想了一个办法:合并检测。即将从多个人( k 个)采集的标本放到同一个试剂盒中进行检测。如果结果为阴性,则说明这 k 个人都是阴性,用一个试剂盒完成了 k 个人的检测。如果结果为阳性,则说明至少有一个人为阳性,需要将这 k 个人的样本全部重新独立检测(从理论上看,如果检测前 k−1 个人都是…可以推断出第 k 个人是…,但是在实际操作中不会利用此推断,而是将 k 个人独立检测),加上最开始的合并检测,一共使用了 k+1 个试剂盒完成了 k 个人的检测。
A 国估计被测的民众的感染率大概是 1,呈均匀分布。请问 k 取多少能最节省…?
思路:
假设有100个人,那么就有一个人感染.
100个人要试剂盒100/k,另外还要k个.
总共100/k + k
当 k=100/k 即k=10时就小.
答案:10

4:REPEAT 程序

【问题描述】
附件 prog.txt 中是一个用某种语言写的程序。
其中 REPEAT k 表示一个次数为 k 的循环。循环控制的范围由缩进表达,
从次行开始连续的缩进比该行多的(前面的空白更长的)为循环包含的内容。
例如如下片段:
REPEAT 2:
 A = A + 4
 REPEAT 5:
  REPEAT 6:
   A = A + 5
  A = A + 7
 A = A + 8
A = A + 9
该片段中从 A = A + 4 所在的行到 A = A + 8 所在的行都在第一行的
循环两次中。
REPEAT 6: 所在的行到 A = A + 7 所在的行都在 REPEAT 5: 循环中。
A = A + 5 实际总共的循环次数是 2 × 5 × 6 = 60 次。
请问该程序执行完毕之后,A 的值是多少?
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个
整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

思路:
1)先解释数组的含义,数组a表示repeat所在行的缩进长度,数组b表示repeat所在行的循环次数。
2)假设某一行要加上k,其外层有要循环m次,那么就是要加上k*m,假设其外层的外层还有循环,那么继续乘上循环次数。
3)那么我们怎么来找某行的外面嵌套了多少个循环呢,其实就是看缩进长度,如果某行的缩进长度比前面行的缩进长度长,那么这行就嵌套在了循环里面,所以我们只要从后往前找到前面行的缩进比当前行少,而且是最先比当前行少的,乘上其循环次数,然后再继续往前找行的缩进比最先比当前行少的,继续乘上其循环次数。一直这样下去。
4)具体实现看代码。

#include <bits/stdc++.h>
#include <algorithm>
#define mod 1000000007
#define ll long long

using namespace std;

int a[10005],b[10005];
int main()
{
    
      
	freopen("Txt.txt","r",stdin);
	char str[1005];
	int pos,p,r = 0;
	ll sum = 0;
	while(gets(str)){
    
      
		int len = strlen(str);
		pos = 0;
		while(str[pos++] == ' ');
		//pos -= 1;
		if(str[len-1] == ':'){
    
      
			a[++r] = pos;
			b[r] = str[len-2] - '0';
			//a,b只保存repeat所在行的信息。
		}
		else{
    
      
			int t = r;
			int g = str[len-1]-'0';
			int temp = g;
			for(int i = r; i >= 1; i--){
    
      //从后往前扫描。
				if(a[i] < pos){
    
      //第一个比当前行少。
					pos = a[i];//换掉继续找。
				    temp *= b[i];
				}
			}
			sum += temp;
		}
	//	cout << sum << endl;
	}
	cout << sum << endl;
	return 0;
}

答案:241830

6:整除序列

题目链接:https://www.acwing.com/problem/content/2067/

#include <bits/stdc++.h>
#include <algorithm>
#define mod 1000000007
#define ll long long

using namespace std;

ll a[10005];
int main()
{
    
      
	ll n;
	cin >> n;
	while(n){
    
      
		cout << n << " ";
		n /= 2; 
	}
}

7:解码

题目链接:https://www.acwing.com/problem/content/2068/

#include <bits/stdc++.h>
#include <algorithm>
#define mod 1000000007
#define ll long long

using namespace std;

int main()
{
    
      
    char s[105];
    scanf("%s",s);
    int len = strlen(s);
    s[len] = '-';
    for(int i = 0; i < len; i++){
    
      
    	if(s[i+1] >= '0' && s[i+1] <= '9'){
    
      
    		int k = s[i+1] - '0';
    		for(int j = 1; j <= k; j++){
    
      
    			cout << s[i];
			}
		}
		else if(s[i] < '0' || s[i] > '9') cout << s[i];
	}
}

8:走方格

题目链接:https://www.acwing.com/problem/content/2069/
思路:
dp[i][j]表示(1,1)到(i,j)的方法数。
dp[1][1] = 1,i和j都是偶数的地方dp[i][j] = 0
其它地方dp[i][j] = dp[i-1][j]+dp[i][j-1]

#include <bits/stdc++.h>
#include <algorithm>
#define mod 1000000007
#define ll long long

using namespace std;

int main()
{
    
      
    int n,m;
    int dp[55][55];
    cin >> n >> m;
    dp[0][0] = 1;
    dp[1][1] = 1;
    for(int i = 1; i <= n; i++){
    
      
        for(int j = 1; j <= m; j++){
    
      
        	if(i == 1 && j == 1) continue;
        	if(!(i&1) && !(j&1)) dp[i][j] = 0;
            else dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        }
    }
    cout << dp[n][m];
}

9:整数拼接

题目链接:
https://www.acwing.com/problem/content/2070/
思路:
假设a[i]和a[j]进行拼接,那么得到的数是(a[i](10^(log10(a[j])+1) + a[j])%k = 0, 即(a[i]%k(10^(log10(a[j])+1)%k + a[j]%k)%k = 0, 也就是找出有多少个a[i]乘上10的1~9次方等于(k-a[j]%k)%k.
为什么是(k-a[i]%k)%k呢,很简单,因为所有数都模了k,也就是说所有数最后都会小于等于k,那么要最后的数模等于0,那只能是相加后等于k模k才会等于0.
用cnt[i][j]记录某个数乘上10^i等于j有多少个.

#include <bits/stdc++.h>
#include <algorithm>
#include <cmath>
#define mod 1000000007
#define ll long long

using namespace std;

ll cnt[15][100005];
ll a[100005];
int main()
{
    
      
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i = 1; i <= n; i++)
	    scanf("%d",&a[i]);
	ll sum = 0;
	for(int i = 1; i <= n; i++){
    
      
		sum += cnt[int(log10(a[i])+1)][(k - a[i]%k)%k];
		ll res = 10;
		for(int j = 1; j <= 10; j++){
    
      
			cnt[j][a[i]%k*res%k]++;
			res *= 10;
		}
	} 
	memset(cnt,0,sizeof(cnt));
	reverse(a+1,a+n+1);
	for(int i = 1; i <= n; i++){
    
      
		sum += cnt[int(log10(a[i])+1)][(k - a[i]%k)%k];
		ll res = 10;
		for(int j = 1; j <= 10; j++){
    
      
			cnt[j][a[i]%k*res%k]++;
			res *= 10;
		}
	} 
	printf("%lld\n",sum);
	return 0;
}

10:网络分析

题目链接:https://www.acwing.com/problem/content/2071/
思路:
用lz[i]保存以i为根节点的那些点要加上的信息大小,当要去做连接操作是,如果两个节点的父节点不相同,那么就把lz[父节点]保存的信息传达下去,最后lz数组要重新置为零。
但好像会超时^^

#include <bits/stdc++.h>
#include <algorithm>
#include <cmath>
#define mod 1000000007
#define ll long long

using namespace std;

int a[10005];
ll lz[10005];
ll sum[10005];
int n,m,t,x,y;
int find(int x)
{
    
      
    if(a[x] != x) a[x] = find(a[x]);
    return a[x];
}

void merge(int x,int y)
{
    
      
	x = find(x);
	y = find(y);
	if(x != y){
    
      
		for(register int i = 1; i <= n; i++){
    
      
			int q = find(i);
			sum[i] += lz[q];
			//lz[q] = 0;
		}
		memset(lz,0,sizeof lz);
		a[x] = y;
	}
	return ;
}

int main()
{
    
      
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++) a[i] = i;
	while(m--){
    
      
		scanf("%d%d%d",&t,&x,&y);
		if(t == 1){
    
      
			merge(x,y);
		}
		else{
    
      
			lz[find(x)] += y;
		}
	} 
	for(int i = 1; i <= n; i++){
    
      
		if(i == 1) printf("%lld",sum[i]+lz[find(i)]);
		else printf(" %lld",sum[i]+lz[find(i)]);
	}
    return 0; 
}