第十二届蓝桥杯题解 注释:这段时间正好在写蓝桥杯的题,将部分的题目的解法和大家分享,代码中的网址是该代码蒟蒻当时参考其他大佬的题解文章所在的网址,鸣谢大佬,如有错误,欢迎各位大佬指正 有部分网址是提交答案的oj传送门
A 卡片 暴力枚举即可,注意小错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <bits/stdc++.h> using namespace std;int a[9 ];bool judge (int n) { while (n) { int remp = n % 10 ; if (a[remp] == 0 ) return false ; a[remp]--; n /= 10 ; } return true ; } int main () { for (int i = 0 ; i <= 9 ; i++) { a[i] = 2021 ; } int num = 0 ; while (judge (num+1 )) { num++; } cout<<num; return 0 ; }
B 直线 这道题想了很久,没有想到特别好的办法,只能暴力枚举。 注意当斜率不存在时要单独讨论,最后加上,否则会出bug
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <bits/stdc++.h> using namespace std;struct node { double x; double y; } point[1000000 ]; long long num = 0 ;long long ans = 0 ;map<pair<double , double >, bool > visit; void judge (node p1, node p2) { double x1 = p1.x, x2 = p2.x; double y1 = p1.y, y2 = p2.y; if (x1 == x2) return ; double k = (y2 - y1) / (x2 - x1); double b = (x2 * y1 - y2 * x1) / (x2 - x1); if (!visit[{k, b}]) { visit[{k, b}] = 1 ; ans++; } } int main () { for (int i = 0 ; i < 20 ; i++) for (int j = 0 ; j < 21 ; j++) { point[++num].x = i; point[num].y = j; } for (int i = 1 ; i <= num; i++) { for (int j = i + 1 ; j <= num; j++) { judge (point[i], point[j]); } } cout << ans + 20 ; return 0 ; }
二刷后的代码,更精简了一些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <bits/stdc++.h> using namespace std;map<pair<double , double >, bool > line; long long ans = 0 ;int main () { for (double x1 = 0 ; x1 < 20 ; x1++) for (double y1 = 0 ; y1 < 21 ; y1++) for (double x2 = 0 ; x2 < 20 ; x2++) for (double y2 = 0 ; y2 < 21 ; y2++) { if (x1 == x2) continue ; double k = (y1 - y2) / (x1 - x2); double b = (y2 * x1 - y1 * x2) / (x2 - x1); if (!line[{k, b}]) ans++; line[{k, b}] = 1 ; } cout << ans + 20 ; return 0 ; }
C 货物摆放 可以考虑将所有的因数直接枚举,然后三重循环判断即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <bits/stdc++.h> using namespace std;long long ans = 0 ;long long tar = 2021041820210418 ;vector<long long > a; int main () { long long remp = tar; for (int i = 1 ; i <= sqrt (remp); i++) { if (remp % i == 0 ) { a.push_back (i); if (i * i != remp) a.push_back (remp / i); } } int len = a.size (); for (int i = 0 ; i < len; i++) for (int j = 0 ; j < len; j++) for (int k = 0 ; k < len; k++) if (a[i] * a[j] * a[k] == tar) ans++; cout << ans; return 0 ; }
D 路径 额,这道题就是最短路问题,弗洛伊德会超时,但是问题不大(反正可以等答案出来之后再交一个答案上去)。迪杰斯特拉似乎不会超时,两种解法都粘在下面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <bits/stdc++.h> using namespace std;int edge[2030 ][2030 ];int gcd (int x, int y) { if (y == 0 ) return x; else return gcd (y, x % y); } int lcm (int x, int y) { return x / gcd (x, y) * y; } int main () { memset (edge, 0x3f , sizeof (edge)); for (int i = 1 ; i <= 2021 ; i++) for (int j = i + 1 ; j <= 2021 ; j++) { if (j - i > 21 ) continue ; int cost = lcm (i, j); edge[i][j] = cost; edge[j][i] = cost; } for (int k = 1 ; k <= 2021 ; k++) for (int i = 1 ; i <= 2021 ; i++) for (int j = 1 ; j <= 2021 ; j++) { edge[i][j] = min (edge[i][k] + edge[k][j], edge[i][j]); } cout<<edge[1 ][2021 ]; return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f int edge[2030 ][2030 ];int path[2030 ];bool visit[2030 ];int gcd (int x, int y) { if (y == 0 ) return x; else return gcd (y, x % y); } int lcm (int x, int y) { return x / gcd (x, y) * y; } int main () { memset (edge, INF, sizeof (edge)); for (int i = 1 ; i <= 2021 ; i++) for (int j = i + 1 ; j <= 2021 ; j++) { if (j - i > 21 ) continue ; int cost = lcm (i, j); edge[i][j] = cost; edge[j][i] = cost; } memset (visit, 0 , sizeof (visit)); memset (path, INF, sizeof (path)); path[1 ] = 0 ; for (int i = 1 ; i <= 2021 ; i++) { int start, min1 = INF; for (int j = 1 ; j <= 2021 ; j++) { if (!visit[j] && path[j] <= min1) { min1 = path[j]; start = j; } } visit[start] = 1 ; for (int j = 1 ; j <= 2021 ; j++) { path[j] = min (path[j], path[start] + edge[start][j]); } } cout << path[2021 ]; return 0 ; }
E 回路数 这道题是状态压缩数组,具体注释看代码,更直观
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <bits/stdc++.h> using namespace std;bool edge[30 ][30 ];const int N = 22 , M = 1 << 21 ; long long dp[M][30 ]; int gcd (int x, int y) { if (y == 0 ) return x; else return gcd (y, x % y); } bool judge (int x, int y) { if (gcd (x, y) == 1 ) return true ; else return false ; } int main () { for (int i = 1 ; i <= 21 ; i++) for (int j = 1 ; j <= 21 ; j++) if (judge (i, j)) edge[i][j] = 1 ; dp[1 ][1 ] = 1 ; for (int i = 1 ; i <= M - 1 ; i++) for (int j = 1 ; j <= 21 ; j++) if (i >> (j - 1 ) & 1 ) for (int k = 1 ; k <= 21 ; k++) if (edge[k][j] && (i - (1 << (j - 1 ))) >> (k - 1 ) & 1 ) { dp[i][j] += dp[(i - (1 << (j - 1 )))][k]; } long long ans = 0 ; for (int i = 2 ; i <= 21 ; i++) { ans += dp[M - 1 ][i]; } cout << ans; return 0 ; }
F 砝码称重 类背包,暴力枚举即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <bits/stdc++.h> using namespace std;#define maxn 200000 int n;long long sum = 0 ;int cost[110 ];bool dp[110 ][maxn]; int main () { ios::sync_with_stdio (false ); cin >> n; for (int i = 1 ; i <= n; i++) cin >> cost[i], sum += cost[i]; for (int i = 1 ; i <= n; i++) for (int j = 1 ; j <= sum; j++) { dp[i][j] = dp[i - 1 ][j]; if (dp[i-1 ][j] == 0 ) { if (cost[i] == j) dp[i][j] = 1 ; if (dp[i - 1 ][j + cost[i]]) dp[i][j] = 1 ; if (dp[i - 1 ][abs (j - cost[i])]) dp[i][j] = 1 ; } } long long ans = 0 ; for (int i = 1 ; i <= sum; i++) if (dp[n][i]) ans++; cout << ans; return 0 ; }
F 左儿子右兄弟 树形dp 关键是:对于任意一个子节点,它的最大深度是子节点的子树最大深度+儿子数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <bits/stdc++.h> using namespace std;vector<int > edge[100000 ]; int dp[1000090 ]; void dfs (int x) { int len=edge[x].size (); int max1=0 ; for (int i=0 ;i<len;i++) { int son=edge[x][i]; dfs (son); max1=max (max1,dp[son]); } dp[x]=max1+len; } int main () { int n; cin >> n; for (int i = 2 ; i <= n; i++) { int remp; cin >> remp; edge[remp].push_back (i); } dfs (1 ); cout << dp[1 ]; return 0 ; }