赞
踩
目录
试题来源:蓝桥杯2020第十一届C语言B组省赛习题题解_shall_zhao的博客-CSDN博客_蓝桥杯c语言题目
思路解析:遍历1~2020,统计每个数字中2的次数,运用到拆分数字的基本算法
- #include<iostream>
- using namespace std;
-
- int cal(int num)
- {
- int cnt = 0;
- while (num)
- {
- int j = num % 10;
- if (j == 2) cnt++;
- num /= 10;
- }
- return cnt;
- }
-
- int main()
- {
- int res = 0;
- for (int i = 1; i <= 2020; i++)
- {
- res += cal(i);
- }
-
- cout << res << endl;//答案为624
-
- return 0;
- }

思路解析:两层内外循环遍历1~2020,用欧几里得算法判断是否是两数的最大公约数为1,统计个数即可
- #include<iostream>
- using namespace std;
-
- int gcd(int a, int b)
- {
- return b ? gcd(b, a % b) : a;
- }
-
- int main()
- {
- int res = 0;
- for(int i=1;i<=2020;i++)
- for (int j = 1; j <= 2020; j++)
- {
- if (gcd(i, j) == 1) res++;
- }
- cout << res << endl;//答案为:2481215
-
- return 0;
- }

问题: 根据此规律,推断第20行20列的数字是多少,其中第2行第2列的数字为5
思路解析:
(1)对于奇数行有:比如说数字‘4’的那一行,则有:从它向它的右上角方向依次+1
(2)对于偶数行有:比如说数字‘10’的那一行,则有:从它向它的右上角方向依次-1
那么同理:
(3)对于奇数列有:比如说数字‘6’的那一列,则有:从它向它的左下角方向依次-1
(4)对于偶数列有:比如说数字‘7’的那一列,则有:从它向它的左下角方向依次+1
那么就有:
定义一个计数器cnt=1,循环for一次,同时枚举(i)行数和列数,如果这个(i)为奇数,那么就让它对应(1)情况,让它向右上角方向++;同理如果这个(i)为偶数,那么就让它对应(4)情况,让它向它的左下角方向++,其中是将cnt的值赋给这个二维数组,并++,最后输出对应行数和列数即可
- #include<iostream>
- using namespace std;
- const int N = 110;
- int a[N][N];
-
- int main()
- {
- int cnt = 1;
- int x, y;
- for (int i = 1; i <= N; i++)
- {
- if (i % 2 == 1)
- {
- for (x = i, y = 1; x >= 1 && y <= i; x--, y++)
- {
- a[x][y] = cnt++;
- }
- }
- else
- {
- for (x = 1, y = i; x <= i && y >= 1; x++, y--)
- {
- a[x][y] = cnt++;
- }
- }
- }
- cout << a[20][20] << endl;
-
- return 0;
- }

问题:
思路解析:
最外层循环枚举年份,接着二判断是否是闰年,如果是闰年,那么就让原先定义好的二月天数改为29,接着内循环枚举月份,接着内循环枚举月份中的天数,如果天数是1,或者为周一,那么就让sum+=2,否则则为普通日子:让sum+=1,枚举完一天后,让星期++,并对7取模,注意枚举该年份后,需要将2月的天数重新修改为28
- #include<iostream>
- using namespace std;
-
- int months[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
- int main()
- {
- int year1 = 2000, year2 = 2020;
- int month1 = 1, month2 = 10;
- int day1 = 1, day2 = 1;
- int week = 6;
-
- long long sum = 0;
-
- for (year1; year1 <= year2; year1++)
- {
- if ((year1 % 400 == 0) || (year1 % 4 == 0 && year1 % 100 != 0))
- {
- months[2] = 29;
- }
- for (int i = 1; i <= 12; i++)
- {
- for (int day = 1; day <= months[i]; day++)
- {
- if (day == 1 || week == 1)
- {
- sum += 2;
- }
- else
- {
- sum += 1;
- }
- week = (week + 1) % 7;
- if (year1 == 2020 && i == 10 && day == 1)
- {
- cout << sum << endl;//答案为:8879
- return 0;
- }
- }
- }
- months[2] = 28;
- }
-
- return 0;
- }

题目概述:
必须要相邻才能发光,也就是所有开着的灯必须是连通的,才能算是一种合法方案,求合法的方案数
- #include<iostream>
- using namespace std;
-
- int use[10];
- int ans, e[10][10], father[10];
-
- void init()
- {
- //连边建图
- //a b c d e f g
- //1 2 3 4 5 6 7
- e[1][2] = e[1][6] = 1;
- e[2][1] = e[2][7] = e[2][3] = 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][1] = e[6][5] = e[6][7] = 1;
- }
-
- int find(int a)
- {
- //并查集
- return (a == father[a]) ? a : father[a] = find(father[a]);
-
- }
- void dfs(int d)
- {
- if (d > 7)//一个七段管的所有灯的状态已经列举完了
- {
- for (int i = 1; i <= 7; i++)
- {
- father[i] = i;//初始化
- }
- for (int i = 1; i <= 7; i++)
- {
- for (int j = 1; j <= 7; j++)
- {//如果存在这条边 且 开i节点 且 开j节点
- if (e[i][j] && use[i] && use[j])
- {
- int fa = find(i), fb = find(j);//寻找i,j对于的祖宗节点
- if (fa != fb)//如果祖宗节点不同,证明未连通
- {
- father[fa] = fb;//连通 a b
- }
- }
- }
- }
-
- int k = 0;
- for (int i = 1; i <= 7; i++)
- {
- if (use[i] && i == father[i])//如果它被用过 且 它等于它的祖宗节点
- k++;
- }
- if (k == 1)//只有一个父节点,就说明他们是相连的
- ans++;
- return;
- }
-
- use[d] = 0;//不选
- dfs(d + 1);
-
- use[d] = 1; //选
- dfs(d + 1);
- use[d] = 0;//归位
- }
- int main()
- {
- init();
- dfs(1);
- cout << ans << endl;
- return 0;
- }

格式化输出的陷阱://格式化输出%的陷阱:要输入%%才表示 %
- #include<iostream>
- using namespace std;
- int main()
- {
- int n;
- cin >> n;
- double a = 0;
- double b = 0;
- int x;
- for (int i = 1; i <= n; i++)
- {
- cin >> x;
- if (x >= 60) a++;
- if (x >= 85) b++;
- }
- //格式化输出%的陷阱:要输入%%才表示 %
- printf("%.0lf%%\n%.0lf%%", a / (n/100.0), b / (n/100.0));
-
- return 0;
- }

思路解析:
本题于与Acwing上的回文日期差不多 466. 回文日期 - AcWing题库
通过Acwing的这题,可以得到的经验是:遍历前四位数,然后进行回文构造,然后再判断构造出来的回文串是否满足日期的标准,即判断它是否是合法的日期,即可
先贴一下Acwing上的回文日期的答案:
- #include <cstdio>
- #include <cstring>
- #include <iostream>
- #include <algorithm>
-
- using namespace std;
-
- int months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
- bool check(int date)
- {
- int year = date / 10000;
- int month = date % 10000 / 100;
- int day = date % 100;
-
- if (!month || month >= 13 || !day) return false;
-
- if (month != 2 && day > months[month]) return false;
- if (month == 2)
- {
- bool leap = year % 4 == 0 && year % 100 || year % 400 == 0;
- if (day > 28 + leap) return false;
- }
-
- return true;
- }
-
- int main()
- {
- int date1, date2;
- cin >> date1 >> date2;
-
- int res = 0;
- for (int i = 1000; i < 10000; i++)
- {
- int x = i, r = i;//构造后四个:先构造回文串,再判断其是否合法
- for (int j = 0; j < 4; j++) r = r * 10 + x % 10, x /= 10;
-
- if (r >= date1 && r <= date2 && check(r)) res++;
- }
-
- printf("%d\n", res);
- return 0;
- }

那么此题与Acwing上不同的地方在于:
输入是一个合法的八位数的日期
第一个输出是,这个日期之后的第一个合法的回文日期
第二个输出是,这个日期之后的第一个符合ABABBABA的日期
注意注释的一些细节即可
- #include<iostream>
- #include<cstdio>
- using namespace std;
-
- int months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
- bool check(int date)//判断是否位合法日期
- {
- int year = date / 10000;
- int month = date % 10000 / 100;
- int day = date % 100;
-
- //如果月份为0 || 月份大于等于13 || 日数为0
- if (!month || month >= 13 || !day) return false;
-
- //如果月份!=2 && 日数大于该月的天数
- if (month != 2 && day > months[month]) return false;
- if (month == 2)
- {
- bool leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
- if (day > 28 + leap) return false;//如果二月的天数>大于原本的二月天数+(可能的闰年+1的天数)
- }
- return true;
- }
-
- bool checkAB(int s)//判断AB
- {
- bool flag = false;
- int y, m, d;
- y = s / 10000; // 得到年份
- m = (s / 100) % 100; // 得到月份 (BA)
- d = s % 100; // 得到日 (BA)
-
- int k, n;
- k = y / 100; // AB
- n = y % 100; // AB
- if (k == n && m == d) // 判断是否为ABABBABA
- {
- flag = true;
- }
- return flag;
- }
-
- int main()
- {
- int date;
- cin >> date;
-
- int flag = 0;
- for (int i = (date/10000) +1; i <= 9999; i++)//枚举四位数的年份
- { //举例 i=1234
- int left = i;
- int right = i;//构造出来的回文串,构造出来的回文串即:12344321
- for (int j = 0; j < 4; j++)
- {
- right = right * 10 + left % 10;//1234*10+1234%10
- left = left / 10;//得到left的下一位
- }//因为是按顺序进行的枚举,所以先符合条件的第一个必然是顺序最小的那一个
- if (check(right))
- {
- flag++;//保证第一个符合的回文串只有一个输出
- if (flag == 1) cout << right << endl;
- if (checkAB(right))
- {
- cout << right << endl;
- return 0;
- }
- }
- }
- }

(1)暴力思路解析:哈希表存储字母出现的次数,查看哈希表中是否有多个字母即可
最外层循环枚举一次走的步长
第二层循环枚举左端点
第三层循环将左端点~~~左端点+步长的这一段距离 赋值
查找哈希表中是否存在元素,如果存在即 res++
memset:重新初始化哈希表
cout<<res<<endl;
- #include<iostream>
- #include<algorithm>
- #include<cstring>
- #include<string>
- using namespace std;
-
- int main()
- {
- string s;
- cin >> s;
-
- int n = s.size();
- int cnt[27] = { 0 };
- int res = 0;
-
- for (int len = 1; len <= n; len++)//枚举长度
- {
- for (int i = 0; i + len <= n; i++)//枚举左端点
- {
- for (int j = i; j < i + len; j++)//将该段进行填充
- {
- cnt[s[j] - 'a']++;
- }
- for (int k = 0; k < 26; k++)//查找
- {
- if (cnt[k] != 0) res++;
- }
- memset(cnt, 0, sizeof cnt);//重新赋值为:0
- }
- }
-
- cout << res << endl;
-
- return 0;
- }

(2)小优化:变成两层循环
- #include<iostream>
- #include<string>
- #include<cstring>
- using namespace std;
-
- const int N = 10010;
- char str[N];
- bool st[26];
-
- int main()
- {
- scanf("%s", str + 1);
- int n = strlen(str + 1);
-
- long long ans = 0;
- for (int i = 1; i <= n; i++)
- {
- memset(st, 0, sizeof st);
- int t = str[i] - 'a';
- st[t] = true;
- int cnt = 1;
- ans += cnt;
- for (int j = i - 1; j >= 1; j--)
- {
- int t = str[j] - 'a';
- if (!st[i])
- {
- cnt++;
- st[t] = true;
- }
- ans += cnt;
- }
- }
-
- printf("%lld\n", ans);
-
- return 0;
- }

(3)大优化
- #include<iostream>
- #include<cstring>
- using namespace std;
- typedef long long ll;
- int last[127];
-
- int main()
- {
- string s;
- cin >> s;
-
- int n = s.size();
- s = ' ' + s;
-
- ll ans = 0;
- for (int i = 1; i <= n; i++)
- {
- ans += (ll)(i - last[s[i]]) * (n - i + 1);
- last[s[i]] = i;
- }
-
- cout << ans << endl;
-
- return 0;
- }

- #include<iostream>
- #include<set>
- using namespace std;
-
- typedef pair<double, double> pdd;
- set<pdd> lines;
- int res = 1;
-
- int cmp(double c, double d)//求此条直线与之前所有直线的交点的个数
- {
- set<pdd> points;
- pdd it;
- for (auto i = lines.begin(); i != lines.end(); i++)
- {
- double a = i->first;
- double b = i->second;
- if (a != c)//斜率不同,则两条直线不重合
- {
- it.first = (d - b) / (a - c);//求交点的横坐标
- it.second = c * it.first + d;//纵坐标
- points.insert(it);
- }
- }
- return points.size();
- }
-
- int main()
- {
- int n;
- cin >> n;
-
- while (n--)
- {
- double a, b;
- cin >> a >> b;
- int count1 = lines.size();
- lines.insert({ a,b });
- if (lines.size() != count1)
- {
- res++;
- res += cmp(a, b);
- }
- }
-
- cout << res << endl;
-
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。