A题:门牌制作
题面
思路
遍历1至2020,统计出现2的次数
答案:624
实现
#include <iostream>
using namespace std;
int main()
{
int ans = 0;
for(int i = 1; i <= 2020; i++)
for(int j = i; j; j /= 10)
if(j % 10 == 2) ans ++;
cout << ans << endl;
return 0;
}
B题:既约分数
题面
思路
分子分母都遍历1至2020,判断它们的最大公约数
实现
#include <iostream>
using namespace std;
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int main()
{
int ans = 0;
for(int i = 1; i <= 2020; i++)
for(int j = 1; j <= 2020; j++)
if(gcd(i, j) == 1) ans++;
cout << ans << endl;
return 0;
}
答案:2481215
C题:蛇形填数
题面
思路
1.根据题目规律构建出矩阵
2.用一个flag表示方向,向上走或者向下走
实现
#include <iostream>
using namespace std;
const int I = 19, J = 19;
int a[100][100];
int main()
{
int cnt = 1;
int i = 0, j = 0;
bool flag = true;
while(i <= I || j <= J)
{
a[i][j] = cnt++;
if(flag && i - 1 < 0) j++, flag = false; // 往上走, 并且走不了
else if(!flag && j - 1 < 0) i++, flag = true;//往下走, 并且走不了
else if(flag) i--, j++;//往上走
else i++, j--;//往下走
}
for(int i = 0; i <= I; i++)
{
for(int j = 0; j <= J; j++)
cout << a[i][j] << '\t';
cout << endl;
}
cout << a[19][19] << endl;
return 0;
}
答案:761
D题:七段码
题面
思路
七段码每一管只有亮灭两种,不考虑连通则有127种(除掉全灭)。所以用二进制枚举1到127,每一位的0或1代表管的亮或灭。
用dfs遍历某一条亮的管,如果一次dfs没遍历完所有亮灯管,说明亮的管不连通,方案不计数
实现
#include <iostream>
#include <cstring>
using namespace std;
bool a[8][8];//a[i][j]表示i能到达j
bool st[8], light[8];
void dfs(int u)
{
st[u] = true;
for(int i = 1; i <= 7; i++)//如果没染过色,是亮的,而且有路径可以到达,就进行染色
if(!st[i] && light[i] && a[u][i]) dfs(i);
}
int main()
{
//下标1234567分别代表abcdefg
a[1][2] = a[2][1] = a[1][6] = a[6][1] = true;
a[2][3] = a[3][2] = a[2][7] = a[7][2] = true;
a[3][4] = a[4][3] = a[3][7] = a[7][3] = true;
a[4][5] = a[5][4] = true;
a[5][6] = a[6][5] = a[5][7] = a[7][5] = true;
a[6][7] = a[7][6] = true;
int ans = 0;
for(int i = 1; i <= 127; i++)
{
memset(st, 0, sizeof st);
memset(light, 0, sizeof light);
for(int k = 0; k < 7; k++)// 记录第几位是1
if(i >> k & 1) light[k + 1] = true;
// 找到第一个亮的管
int j = 1;
while(light[j] == false) j++;
dfs(j);//染色
//染色过后如果还有无法到达的亮灯管,则说明至少有两个连通块
bool flag = true;
for(int k = 1; k <= 7; k++)
if(light[k] && !st[k])
flag = false;
if(flag) ans++;
}
cout << ans << endl;
return 0;
}
答案:80
E题:平面分割
题面
思路
纯数学题,参考:2020年蓝桥杯---A组省赛E题---平面分割(数学)_雪岩的博客-优快云博客_平面分割 蓝桥杯
F题:成绩分析
题面
思路
纯粹的语法题。printf在输出截断位小数时,会进行四舍五入,不需要特殊处理。
实现
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e4 + 10;
int a[N];
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
int minx = 110, maxx = -1;
double sum = 0;
for(int i = 0; i < n; i++)
{
minx = min(minx, a[i]);
maxx= max(maxx, a[i]);
sum += a[i];
}
printf("%d\n%d\n%.2f\n", maxx, minx, sum / n);
return 0;
}
G题:回文日期
题面
思路
遍历10000101至89991231,找出合法的,并且是回文的日期。对于第二个答案,再从第一个答案找到的位置开始,判断是不是ABABBABA型
实现
#include <cstdio>
using namespace std;
char str[8];
//把数字转化成字符串,蓝桥杯练习系统不支持C++11,不能用to_string
void tostring(int n)
{
for(int i = 7; i >= 0; i--)
{
str[i] = n % 10;
n /= 10;
}
}
bool pali(int n)//判断是否是回文
{
tostring(n);
for(int i = 0, j = 7; i <= j; i++, j--)
if(str[i] != str[j]) return false;
return true;
}
bool leap(int year)//闰年判断
{
//能被四百整除或者,能被四整除且不能被一百整除
if(year % 400 == 0) return true;
if(year % 100 && year % 4 == 0) return true;
return false;
}
bool legal(int n)//判断日期是否合法
{
// 首先判定月份是否合法
int month = (n / 1000 % 10) * 10 + n / 100 % 10;
if(month == 0 || month > 12) return false;
//日数判断
int day = (n / 10 % 10) * 10 + n % 10;
if(day == 0) return false;
switch(month)
{
case 1 :
if(day > 31) return false;
case 2 :
if(leap(n / 10000) && day > 29) return false;
else if(day > 28) return false;
case 3 :
if(day > 31) return false;
case 4 :
if(day > 30) return false;
case 5 :
if(day > 31) return false;
case 6 :
if(day > 30) return false;
case 7 :
if(day > 31) return false;
case 8 :
if(day > 31) return false;
case 9 :
if(day > 30) return false;
case 10:
if(day > 31) return false;
case 11:
if(day > 30) return false;
case 12:
if(day > 31) return false;
}
return true;
}
bool abcase(int n)//判定ABABBABA型
{
//这里的str不需要更新,pali 总是运行在abcase前面,总会优先把str更新
char a = str[0], b = str[1];
if(str[2] == a && str[5] == a && str[7] == a && str[3] == b && str[4] == b && str[6] == b)
return true;
return false;
}
int main()
{
int n;
scanf("%d", &n);
do n++;
while(!legal(n) || !pali(n));
printf("%d\n", n);
while(!legal(n) || !pali(n) || !abcase(n)) n++;
printf("%d\n", n);
return 0;
}
H题:子串分值
题面
思路
考虑对于字符串中的每一个字母,有多少个子串它能贡献一个1。
例如: @C@@@C@@C @表示除C以外的字母
设l,r分别为子串和右串能取到的下标
对于第一个字母C,l可以取l = 1,2;r可以取 r = 2,3,4,5
所以有2 x 4 = 6个子串对于答案有贡献
对于第二个字母C,l可以取l = 3,4,5,6;r可以取 r = 6,7,8
所以有4 x 3 = 12个子串对于答案有贡献
对于第三个字母C,l可以取l = 6,7,8;r可以取 r = 8
所以有3 x 1 = 3个子串对于答案有贡献
故只需要遍历字符串,计算每一个字符对答案的贡献值。
首先用一个栈数组存储每种字母出现的位置。计算每一个字符的同时,更新每种字母的pre值,对于下一个这种字母的下标,可以在栈中找到。
实现
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
const int N = 1e5 + 10, M = 26;
typedef long long LL;
int n, pre[M];//表示前面的字母位置
char str[N];
vector<stack<int> > vec(M);
int main()
{
scanf("%s", str + 1);
n = strlen(str + 1);
//将每种字母出现的位置压入栈中,栈顶是每种字母最先出现的位置
for(int i = n; i > 0; i--)
{
int ch = str[i] - 'a';
vec[ch].push(i);
}
LL ans = 0;
for(int i = 1; i <= n; i++)
{
int ch = str[i] - 'a';
//计算左右两边有多少种可能性
int r = n - i + 1, l = i - pre[ch];
vec[ch].pop();//顶部记录的是当前i,不需要
if(vec[ch].size()) r = vec[ch].top() - i;
ans += l * r;
pre[ch] = i;//保存当前i以备下一个相同的ch使用
}
cout << ans << endl;
return 0;
}
//参考自:https://blog.youkuaiyun.com/LUSH_BOY/article/details/114606213?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-3-114606213.pc_agg_new_rank&utm_term=%E8%93%9D%E6%A1%A5%E6%9D%AF%E5%AD%90%E4%B8%B2%E5%88%86%E5%80%BCC%2B%2B&spm=1000.2123.3001.4430