HAUT2021蓝桥杯专题练习第一周记录——枚举

HAUT2021蓝桥杯专题练习第一周记录——枚举

学长们挑选了一些CF的题目放到了VJ上进行专题练习,第一周的题目相对比较简单(基本上都是CF的A题)苦于是英文题,基本上全程去洛谷找的翻译然而我是个菜鸡,有几道题还是想了好久才想出来,有的还是去参考了别人的题解。
记录一下留个纪念。

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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值