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

A-门牌制作

在这里插入图片描述

【答案】

624

【参考程序】

#include <stdio.h>

int main()
{
	int cnt=0;
	for(int i=1;i<=2020;i++)
	{
		int j=i;
		while(j)
		{
			if(j%10==2)
				cnt++;
			j/=10;
		}
	}
	printf("%d",cnt);
	
	return 0;
}

B-既约分数

在这里插入图片描述

【答案】

2481215

【解题思路】
gcd函数用于计算最大公约数,效率较高。当时用的暴力法,也能跑出结果。

【参考程序1】

#include <stdio.h>

int gcd(int a,int b)
{
	if(b==0)
		return a;
	else
		return gcd(b,a%b);
}
int main()
{
	int cnt=0;
	for(int i=1;i<=2020;i++)
		for(int j=1;j<=2020;j++)
			if(gcd(i,j)==1) cnt++;	
	printf("%d",cnt);
	
	return 0;
} 

【参考程序2】

#include <stdio.h>

bool IsPrim(int a,int b)
{
	for(int i=2;i<a;i++)
		if(a%i==0&&b%i==0)
			return false;
	return true;
}
int main()
{
	int cnt=0;
	for(int i=1;i<=2020;i++)
		for(int j=1;j<i;j++)
			if(IsPrim(i,j)) 
				cnt+=2; // a/b 与 b/a 算两种 
	printf("%d",cnt+1); // 1/1 作单独考虑 
	
	return 0;
}

C-蛇形填数

在这里插入图片描述

【答案】

761

【解题思路】
找规律,主对角线元素依次递增4的倍数,可以再写几个数来验证。

【参考程序】

#include <stdio.h>

int main()
{
	int ret=1;
	for(int i=1;i<20;i++)
	{
		ret+=i*4;
	}
	printf("%d",ret);
	
	return 0;
}

D-跑步锻炼

在这里插入图片描述

【答案】

8879

【注意事项】
注意闰年的判断即可。

【参考程序】

#include <stdio.h>

int Month[12]={31,29,31,30,31,30,31,31,30,31,30,31};
int main()
{
	int year=2000;
	int month=1;
	int day=1;
	int week=6;
	int cnt=0;
	while(year<2020||month<10||day==1)
	{
		if(day==1||week==1)
			cnt+=2;
		else
			cnt++;
		if(day==Month[month-1])
		{
			day=1;
			if(month==12)
			{
				month=1;
				year++;
				if((year%4==0&&year%100!=0)||(year%400==0))
					Month[1]=29;
				else Month[1]=28;
			}else
				month++;
		}else
			day++;
		week=(week+1)%7;
	}
	printf("%d",cnt);
	
	return 0;
}

E-七段码

在这里插入图片描述

【答案】

80

【解题思路】
采用dfs+并查集的方法,dfs用于枚举所有可能的情况,并查集判断是否连成一片。
对于并查集不了解的可以查看 算法学习笔记(1):并查集

【参考程序】

#include <stdio.h>
#define MAXN 10

//a-1 b-2 c-3 d-4 e-5 f-6 g-7
int fa[MAXN];
int e[MAXN][MAXN]={};
int ans=0;
int v[MAXN]={};
void init()
{
	for(int i=0;i<MAXN;i++)
		fa[i]=i;
}
int find(int x)
{
	return fa[x]==x?x:(fa[x]=find(fa[x]));
}
void merge(int i,int j)
{
	fa[find(i)]=find(j);
}
void dfs(int n)
{
	init();
	if(n>7)
	{
		for(int i=1;i<=7;i++)
			for(int j=1;j<i;j++)
				if(e[i][j]==1&&v[i]==1&&v[j]==1)
				{
					int fx=find(i),fy=find(j);
					if(fx!=fy) fa[fx]=fy; //merge(i,j);
				}
		int k=0;
		for(int i=1;i<=7;i++)
			if(v[i]&&fa[i]==i) k++;
		if(k==1) ans++;
		return;
	}
	v[n]=1;
	dfs(n+1);
	v[n]=0;
	dfs(n+1);
}
int main()
{
	//刻画连通关系 
	e[1][2]=e[1][6]=1;
	e[2][1]=e[2][3]=e[2][7]=1;
	e[3][2]=e[3][4]=e[3][7]=1;
	e[4][3]=e[4][5]=1;
	e[5][4]=e[5][6]=e[5][7]=1;
	e[6][5]=e[6][7]=e[6][1]=1;
	e[7][2]=e[7][3]=e[7][5]=e[7][6]=1;
	
	dfs(1);
	printf("%d",ans);
	
	return 0;
} 

F-成绩统计

提交程序请点击 这里
在这里插入图片描述
【样例输入】

7
80
92
56
74
88
100
0

【样例输出】

71%
43%

在这里插入图片描述

【参考程序】

#include <stdio.h>

int main()
{
	int n;
	int grade;
	int pass=0;
	int good=0;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&grade);
		if(grade>=85)
			good++;
		if(grade>=60)
			pass++;
	}
	printf("%.0f%%\n%.0f%%",double(pass)/n*100,double(good)/n*100);
	
	return 0;
}

G-回文日期

提交程序请点击 这里
在这里插入图片描述
【样例输入】

20200202

【样例输出】

20211202
21211212

在这里插入图片描述
【解题思路】
按照年份遍历,然后判断构成的日期是否合法、是否满足题目条件。

【参考程序】

#include <stdio.h>

int Month[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int getTxt(int year)
{
	int ret=year;
	int month=year%10;
	year/=10;
	month=month*10+year%10;
	year/=10;
	int day=year%10;
	year/=10;
	day=day*10+year%10;
	ret=ret*100+month;
	ret=ret*100+day;
	return ret;
}
bool IsLegal(int year)
{
	int month=year%10;
	year/=10;
	month=month*10+year%10;
	year/=10;
	int day=year%10;
	year/=10;
	day=day*10+year%10;
	if(month<1||month>12)
		return false;
	int Mday=Month[month-1];
	if(month==2&&((year%4==0&&year%100!=0)||(year%400==0)))
		Mday++;
	if(day>Mday)
		return false;
	else
		return true;
}
bool IsBest(int txt)
{
	int num[8]={};
	for(int i=0;i<8;i++)
	{
		num[i]=txt%10;
		txt/=10;
	}
	if(num[0]==num[2]&&num[0]==num[5]&&num[0]==num[7]&&num[1]==num[3]&&num[1]==num[4]&&num[1]==num[6])
		return true;
	else return false;
}
int main()
{
	int n;
	scanf("%d",&n);
	int year=n/10000;
	int txt=getTxt(year);
	while(!IsLegal(year)||txt<=n)
	{
		year++;
		txt=getTxt(year);
	}
	printf("%d\n",txt);
	while(!IsLegal(year)||!IsBest(txt))
	{
		year++;
		txt=getTxt(year);
	}
	printf("%d",txt);
	
	return 0;
}

H-子串分值和

提交程序请点击 这里
在这里插入图片描述
【样例输入】

ababc

【样例输出】

28

在这里插入图片描述
在这里插入图片描述
【解题思路】
法一:需要遍历所有子串,时间复杂度最起码也要O(n2),大概能跑掉6/10个测试点。方法是相同起始位置的子串,记录下前n个字符构成的f值,如果新增加的字母从未出现过,也就是计数值为1,sum加一,代表当前子串的f值。也就是说,每个子串的f值由前一个子串的f值加上新增加的元素的影响来计算。
法二:计算每个字符的贡献度,如果字符各不相同,第i个字符的贡献度为i*(n-i+1),如果有相同的元素出现,要扣除掉已有元素的影响,公式为(i-i上次出现的位置)*(n-i+1)。公式看不懂的戳 这里

【参考程序1】

#include <iostream>
using namespace std;

int main()
{
	long long cnt=0;
	long long sum=0;
	string s;
	cin>>s;
	for(int i=0;i<s.length();i++)
	{
		int character[26]={};
		sum=0;
		for(int j=i;j<s.length();j++)
		{
			character[s[j]-'a']++;
			if(character[s[j]-'a']==1) sum++;
			cnt+=sum;
		}
	}
	cout<<cnt;
	
	return 0;
}

【参考程序2】

#include <iostream>
using namespace std;

int main()
{
	long long cnt=0;
	int last[26]={};
	string s;
	cin>>s;
	int n=s.length();
	for(int i=1;i<=n;i++)
	{
		int j=s[i-1]-'a'; 
		cnt+=1ll*(i-last[j])*(n-i+1);
		last[j]=i;
	}
	cout<<cnt;
	
	return 0;
} 

I-平面切分

提交程序请点击 这里
在这里插入图片描述
【样例输入】

3
1 1
2 2
3 3

【样例输出】

6

在这里插入图片描述
【解题思路】
N=0时,平面数为1(用例中不会出现)
N=1时,平面数为2
N=2时,若平行平面数为3,若相交平面数为4
N=3时,至少会新增加一个平面,每与其他直线产生一个交点,产生平面数加一
基于上述想法,对于每条直线,计算与其他直线的交点,然后存入集合中,集合的大小即为不同交点的个数。

【注意事项】
要去除重复直线的影响,当直线平行时无需计算交点。

【参考程序】

#include <iostream>
#include <set>
using namespace std;

long double s[1001][2];
bool st[1001]={};
pair<long double,long double> p;
int main()
{
	int N;
	long long cnt=0;
	cin>>N;
	for(int i=1;i<=N;i++)
	{
		cin>>s[i][0]>>s[i][1];
		set<pair<long double,long double> > points;
		for(int j=1;j<i;j++)
		{
			if(st[j]) continue;
			if(s[i][0]==s[j][0])
			{
				if(s[i][1]==s[j][1])
				{
					st[i]=true;
					break;
				}else continue;
			}
			p.first=(s[j][1]-s[i][1])/(s[i][0]-s[j][0]);
			p.second=s[i][0]*p.first+s[i][1];
			points.insert(p);
		}
		if(!st[i]) cnt+=points.size()+1;
	}
	cout<<cnt+1;
	
	return 0;
} 

【写在最后的话】
双非本科大学生,自认为对算法感兴趣,要求自己写题解,一方面是对自身掌握情况作一个总结,也希望能帮助到大家。参考了非常多的博客、题解,在此也就不一一列举了。
最后一题还没吃透,有时间再更新~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值