HAUT2021蓝桥杯专题练习第一周记录——枚举
学长们挑选了一些CF的题目放到了VJ上进行专题练习,第一周的题目相对比较简单(基本上都是CF的A题)苦于是英文题,基本上全程去洛谷找的翻译然而我是个菜鸡,有几道题还是想了好久才想出来,有的还是去参考了别人的题解。
记录一下留个纪念。
题目列表
- HAUT2021蓝桥杯专题练习第一周记录——枚举
- A Gennady and a Card Game(CF1097A)
- B New Year and the Christmas Ornament(CF1091A)
- C Ehab and another construction problem(CF1088A)
- D Make a triangle!(CF1064A)
- E Mishka and Contest(CF999A)
- F Replacing Elements(CF1473A)
- G Delete from the Left(CF1005B)
- H The Fair Nut and Elevator(CF1084A)
- I Run For Your Prize(CF938B)
- J String LCM(CF1473B)
- K Points on the line(CF940A)
- L Segment Occurrences(CF1016B)
- M Intense Heat(CF1003C)
- N Three displays(CF987C)
- O Make a Square(CF962C)
- P Photo of The Sky(CF1012A)
- Q Beautiful Regional Contest(CF1264A)
- R Pairs(CF1169B)
- S Polygon for the Angle(CF1096C)
- 总结
A Gennady and a Card Game(CF1097A)
简单的枚举,一一进行比对。
AC代码
#include <bits/stdc++.h>
using namespace std;
string s1;
string s;
int main()
{
cin >> s1;
vector<string> res;
for (int i = 0; i < 5; i++)
{
cin >> s;
res.push_back(s);
}
int flag = 1;
for (int j = 0; j < 5; j++)
{
if (s1[0] == res[j][0] || s1[1] == res[j][1])
{
flag = 0;
break;
}
}
if (flag == 1)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
}
return 0;
}
B New Year and the Christmas Ornament(CF1091A)
枚举黄灯数量,然后判断蓝灯和红灯是否够数就可以了。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int y, b, r;
cin >> y >> b >> r;
//y y+1 y+2
for (; y >= 1; y--)
{
if (b >= y + 1 && r >= y + 2)
{
cout << y + y + 1 + y + 2 << endl;
break;
}
}
return 0;
}
C Ehab and another construction problem(CF1088A)
根据题意简单枚举所有可能性,找到第一种就输出之后返回,反之输出-1。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x;
cin >> x;
for (int a = 1; a <= x; a++)
{
for (int b = 1; a % b == 0; b++)
{
if (a * b > x && a / b < x)
{
cout << a << " " << b << endl;
return 0;
}
}
}
cout << -1 << endl;
return 0;
}
D Make a triangle!(CF1064A)
大概算是一个数学题?如果构不成三角形,那么需要的时间就是最大的一条边减去较小的两边和再加一。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int arr[3];
cin >> arr[0] >> arr[1] >> arr[2];
sort(arr, arr + 3);
if (arr[2] < arr[1] + arr[0])
cout << 0 << endl;
else
cout << arr[2] - arr[1] - arr[0] + 1 << endl;
return 0;
}
E Mishka and Contest(CF999A)
难得的洛谷没有翻译。
题意是:在n个数中,从左或者从右小于k的数依次删除,问最多能够删除多少个数。
先从左枚举,如果从左没有枚举完再从右枚举。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, k;
int arr[110] = {0};
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> arr[i];
int cnt = 0;
int flag = 1;
for (int i = 0; i < n; i++)
{
if (arr[i] <= k)
cnt++;
else
{
flag = 0;
for (int j = n - 1; j >= i; j--)
{
if (arr[j] <= k)
{
cnt++;
continue;
}
cout << cnt << endl;
return 0;
}
}
}
if (flag == 1)
cout << cnt << endl;
return 0;
}
F Replacing Elements(CF1473A)
题意:在n个数中,可以用任意两个数的和来替换另外一个数,如果可以使所有数都不大于d,输出yes,反之no。多实例。
如果是yes就是两种情况,一种最大值不大于d,另一种两个最小值的和不大于d。排序判断即可。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
int arr[110];
cin >> t;
while (t--)
{
memset(arr, 0, sizeof(arr));
int n, d;
cin >> n >> d;
for (int i = 0; i < n; i++)
cin >> arr[i];
sort(arr, arr + n);
if (d >= arr[n - 1] || arr[0] + arr[1] <= d)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
return 0;
}
G Delete from the Left(CF1005B)
只能从左往右删除的话,代表最后成立的情况一定是在右边,找出右边还剩下多少个然后再用总字符个数去减就行了。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s1, s2;
cin >> s1;
cin >> s2;
int cnt = 0;
int n = s1.length();
int m = s2.length();
for (int i = n - 1, j = m - 1; i >= 0; i--, j--)
{
if (s1[i] == s2[j])
cnt++;
else
break;
}
cout << m + n - 2 * cnt << endl;
return 0;
}
H The Fair Nut and Elevator(CF1084A)
枚举所有情况找出最少的路程。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
int arr[110];
memset(arr, 0, sizeof(arr));
for (int i = 1; i <= n; i++)
cin >> arr[i];
int res = 1 << 30;
//i表示电梯初始在的楼层
for (int i = 1; i <= n; i++)
{
int cnt = 0;
for (int j = 1; j <= n; j++)
{
//j-i到j楼接人 再下到1楼(j-1)再回到i层(i-1)
//早上和晚上路程使一样的所以 人数*2
cnt += (abs(j - i) + j - 1 + i - 1) * arr[j] * 2;
//如果层数多了就直接break
if (cnt >= res)
break;
}
res = min(cnt, res);
}
cout << res << endl;
return 0;
}
I Run For Your Prize(CF938B)
开一个大点的数组,然后标记礼物所在的位置,再进行模拟,直到礼物都被拿完。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int max_n = 1000010;
int st = max_n - 10;
int arr[max_n] = {0};
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int tmp;
cin >> tmp;
arr[tmp] = 1;
}
int cnt = 0;
for (int i = 1; i < max_n - 10; i++)
{
if (arr[i] == 1)
cnt++;
if (arr[st] == 1)
cnt++;
if (cnt == n)
{
cout << i - 1 << endl;
return 0;
}
st--;
}
return 0;
}
J String LCM(CF1473B)
题目大意:给两个字符串s1,s2。求他们的最小公倍数,没有的话输出-1。多实例。注:假设s1=“ab”,那么s1*2=“abab”
利用C++的string类就可以很好的处理。利用循环让两个字符串长度一样,比较两个字符串是否相等,相等就输出,否者输出-1。
AC代码
#include <bits/stdc++.h>
using namespace std;
string LCM(string s, string t)
{
string s1 = s;
string t1 = t;
while (s.length() != t.length())
{
if (s.length() < t.length())
s += s1;
else
t += t1;
}
if (s == t)
return s;
else
return "-1";
}
int main()
{
int q;
cin >> q;
while (q--)
{
string s, t;
cin >> s;
cin >> t;
cout << LCM(s, t) << endl;
}
return 0;
}
K Points on the line(CF940A)
暴力枚举所有情况,求出最小值。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, d;
cin >> n >> d;
int arr[110] = {0};
for (int i = 0; i < n; i++)
cin >> arr[i];
sort(arr, arr + n);
int res = n;
int cnt = 0;
//i是前面删除了几个
for (int i = 0; i < n; i++)
{
cnt = i;
int _min = arr[i];
//j是后面删除了几个
for (int j = n - 1; j >= i; j--)
{
int _max = arr[j];
if (_max - _min <= d)
res = min(res, cnt);
cnt++;
}
}
cout << res << endl;
return 0;
}
L Segment Occurrences(CF1016B)
一道前缀和的题,当时第一次看到的时候想到了前缀和但是仍然不知道怎么写,看来还是需要再去温习几次。
AC代码
#include <bits/stdc++.h>
using namespace std;
//前缀和数组
int arr[1010] = {0};
int main()
{
int n, m, q;
cin >> n >> m >> q;
string s, t;
cin >> s;
cin >> t;
for (int i = 0; i <= n - m; i++)
{
//在s中i的位置处截取m个字符和t相比较
if (s.substr(i, m) == t)
{
arr[i] = 1;
}
}
while (q--)
{
int l, r;
cin >> l >> r;
int cnt = 0;
for (int i = l - 1; i <= r - m; i++)
{
if (arr[i] == 1)
cnt++;
}
cout << cnt << endl;
}
return 0;
}
M Intense Heat(CF1003C)
前缀和……不过这个感觉更加简单一些,暴力枚举得最大值就行了。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int max_n = 5010;
int arr[max_n];
int buf[max_n];
int main()
{
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
cin >> arr[i];
}
buf[0] = 0;
for (int i = 1; i <= n; i++)
{
//构建前缀和
buf[i] = buf[i - 1] + arr[i];
}
double res = 0.0;
for (int i = k; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
res = max(res, (buf[i + j - 1] - buf[j - 1]) * 1.0 / i);
}
}
printf("%.15lf\n", res);
return 0;
}
N Three displays(CF987C)
暴力枚举O(n3)会超时,选着每次确定中间的位置可以让时间复杂度变成O(n2)。(思路来源于一位大佬)
AC代码
#include <bits/stdc++.h>
using namespace std;
int arr[3100] = {0};
int buf[3100] = {0};
typedef pair<int, int> P;
int main()
{
int n;
vector<P> res;
cin >> n;
for (int i = 0; i < n; i++)
cin >> arr[i];
for (int i = 0; i < n; i++)
cin >> buf[i];
for (int i = 0; i < n; i++)
{
P pt(arr[i], buf[i]);
res.push_back(pt);
}//数据初始化完毕
int cnt = 1 << 30;
for (int j = 1; j < n - 1; j++) //枚举sj
{
int cj = res[j].second;
int l = j - 1, r = j + 1;
int ci = res[l].second;
int ck = res[r].second;
for (int i = j - 1; i >= 0; i--) //找最小满足条件的ci
{
if (res[j].first > res[i].first && res[i].second < ci)
{
l = i;
ci = res[i].second;
}
}
for (int k = j + 1; k < n; k++) //找最小的满足条件的cj
{
if (res[k].first > res[j].first && res[k].second < ck)
{
r = k;
ck = res[k].second;
}
}
if (res[j].first > res[l].first && res[j].first < res[r].first)
cnt = min(cnt, ci + cj + ck);
}
if (cnt == 1 << 30)
cout << "-1" << endl;
else
cout << cnt << endl;
return 0;
}
O Make a Square(CF962C)
dfs暴搜果然爆搜还是属于枚举啊。
使用了string来储存数字,然后使用stoi减少了储存和运算的麻烦。
AC代码
#include <bits/stdc++.h>
using namespace std;
int resl = 1 << 30;
//判断条件成立
bool IsSq(int _n)
{
return (int)sqrt(_n) == sqrt(_n);
}
//前导零
int HZ(string s)
{
int res = 0;
while (s[0] == '0')
{
res++;
s.erase(0, 1);
}
return res;
}
void dfs(int step, string s)
{
int st = stoi(s);
//条件成立跳出
if (st > 0 && IsSq(st))
{
resl = min(resl, step);
return;
}
//只剩下一位数且不成立也跳出
if (st / 10 == 0)
return;
for (int i = 0; i < s.length(); i++)
{
string t = s;
char t1 = t[i];
t.erase(i, 1);
dfs(step + 1 + HZ(t), t);
t.insert(i, 1, t1);
}
}
int main()
{
string s;
cin >> s;
dfs(0, s);
if (resl == 1 << 30)
cout << "-1" << endl;
else
cout << resl << endl;
return 0;
}
P Photo of The Sky(CF1012A)
这道A题我想了老半天没有想出来……看别人的题解也看了好半天才反应过来是个什么情况。菜的离谱TT
首先明确一点,有2n个点,n个x坐标和n个y坐标。
对所有点进行排序好处理数据
矩形面积公式S=(x2-x1)(y2-y1)
要想他最小就有两种情况:
1、要包揽所有的点,x2-x1应该是最大的x坐标减去最小的x坐标。还要让x2-x1和y2-y1尽量相等。
2、要包揽所有的点,x2在最右端,x1在最左端,枚举让y的极差最小。
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<long long, long long> P;
int main()
{
int n;
cin >> n;
vector<long long> point;
for (int i = 0; i < 2 * n; i++)
{
long long t;
cin >> t;
point.push_back(t);
}
//不构成矩形
if (n < 2)
{
cout << 0 << endl;
return 0;
}
//排序
sort(point.begin(), point.end());
//第一种情况
long long x1, y1, x2, y2;
x2 = point[2 * n - 1];
x1 = point[n];
y2 = point[n - 1];
y1 = point[0];
long long res = (x2 - x1) * (y2 - y1);
//第二种情况
long long a = point[2 * n - 1] - point[0];
for (int i = 1; i < n; i++)
{
long long b = point[2 * n - i - 1] - point[n - i];
res = min(res, a * b);
}
cout << res << endl;
return 0;
}
Q Beautiful Regional Contest(CF1264A)
暴力枚举出最少的金牌和最少的银牌与最多的铜牌就行了。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
cin >> T;
while (T--)
{
int n;
cin >> n;
vector<int> arr(n, 0);
for (int i = 0; i < n; i++)
cin >> arr[i];
if (n < 6)
{
cout << "0 0 0" << endl;
continue;
}
int i, cntg = 0, cnts = 0, cntb = 0;
int max_n = arr[0];
for (i = 0; i < n; i++)
{
if (arr[i] == max_n)
cntg++;
else
{
max_n = arr[i];
break;
}
} //最少的金牌
for (; i < n; i++)
{
if (arr[i] == max_n)
cnts++;
else if (cnts <= cntg)
{
max_n = arr[i];
cnts++;
}
else
{
max_n = arr[i];
break;
}
} //最少的银牌
int tmp = 0;
for (; i < n; i++)
{
if (max_n == arr[i])
{
tmp++;
}
else if (cntg + cnts + cntb + tmp > n / 2)
{
break;
}
else
{
max_n = arr[i];
cntb += tmp;
tmp = 1;
}
} //最多的铜牌
//铜牌人数不够
if (cntb <= cntg)
{
cout << "0 0 0" << endl;
}
else
{
cout << cntg << " " << cnts << " " << cntb << endl;
}
}
return 0;
}
R Pairs(CF1169B)
这道题的思路也是来自于网上的一个大佬。
由题意可知,如果条件成立,那么一定是有小于等于4个数的组合。就验证所有的组合就行了。
例如:abcd->ab ac ad bc bd cd
有一组成立即是成立
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
vector<P> p;
bool IsOK(int a, int b)
{
int n = p.size();
for (int i = 0; i < n; i++)
{
if (a == p[i].first || a == p[i].second || b == p[i].first || b == p[i].second)
continue; //成立就继续
else
return false; //有一组不成立就是false
}
return true;
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int x, y;
cin >> x >> y;
P p1(x, y);
p.push_back(p1);
}
//初始化数据
int a, b, c, d;
a = p[0].first;
b = p[0].second;
c = a;
d = a;
//循环找出那4个数
for (int i = 1; i < m; i++)
{
//如果这一组数满足要求就继续循环
if (p[i].first == a || p[i].second == a || p[i].first == b || p[i].second == b)
continue;
//如果第一个数不满足
if (p[i].first != a && p[i].first != b)
{
c = p[i].first;
}
if (p[i].second != a && p[i].second != b)
{
d = p[i].second;
}
}
if (IsOK(a, b) || IsOK(a, c) || IsOK(a, d) || IsOK(b, c) || IsOK(b, d) || IsOK(c, d))
cout << "YES" << endl;
else
cout << "NO" << endl;
return 0;
}
S Polygon for the Angle(CF1096C)
这是一道数学题。在中间画个圆,求边上的角相当于是圆心角的二分之一。所以每次只要知道n边形的一个角是多少度,是否能被所求角整除就可以了。要注意可能有边数不够的情况。
AC代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
cin >> T;
while (T--)
{
double ct;
cin >> ct;
for (int i = 3;; i++)
{
//要求的度数
double t = ct * 2.0;
//一个角多少度
double n = 360.0 / i;
//需要多少条边
double x = t / n;
//剩下1条边,没有三个顶点不符合题意
if (i - x < 2)
continue;
if (x == (int)x)
{
cout << i << endl;
break;
}
}
}
return 0;
}
总结
没想到工作量这么大,已经凌晨1点半了……不过总算是写完了,这次的专题训练还是发现了很多自己的不足,想前缀和知识掌握的不够熟练等等。自己还是要加强这方面的练习啊。争取不要那么菜了555