【算法题解】2022年第四届河南省CCPC大学生程序设计竞赛(喜提银牌)

文章目录

    • A. Mocha 上小班啦
    • E. Serval 的俳句
    • F. 集合之和
    • G. Mocha 上大班啦
    • H. 旋转水管

比赛题目已上传到CF:2022 CCPC Henan Provincial Collegiate Programming Contest

比赛排名:Live: 2022年河南省第四届CCPC大学生程序设计竞赛 | RankLand (algoux.org)

喜提银牌一枚

【算法题解】2022年第四届河南省CCPC大学生程序设计竞赛(喜提银牌)_第1张图片

A. Mocha 上小班啦

这道题我队友从A题开始往后看,直接发现是道签到题,上去就开写,为了防止罚时,我们一起检查了一遍,不希望在小事在出错。最后一发A了。哈哈。

思路:构造

  • 如果n >10,你们肯定不存在,因为要保证数位中各个数字不相同。
  • 如果n <= 10
    • n = 1,答案就是0
    • n > 1,答案是就是10234…

比赛时AC代码

#include 
using namespace std;
#define int long long

signed main()
{
    int n;
    cin >> n;
    if (n > 10)
        cout << -1 << endl;
    else
    {
        if (n == 1)
        {
            cout << 1 << endl;
        }
        else
        {
            cout << "10";
            for (int i = 2; i < n; i++)
            {
                cout << i;
            }
            cout << endl;
        }
    }
    return 0;
}

E. Serval 的俳句

过了一会发现E题过了很多,觉得肯定是道签到题,然后队长让我看,我上去一看发现还真是。

思路:贪心

首先,我们需要现在字符串从前到后找到5个相同字符,然后再再剩下的字符串中找7个字符,再然后在剩下的找5个相同字符,最后就找到了一个正确结果。

为啥这样保证一定正确呢:当时我想的是如果我从字符串的第一位开始找,如果某个字母出现了5次,那么它就一定是最优的,并且只用到了整个字符串最短的部分,那么剩下的同理。

比赛时AC代码

#include 
using namespace std;
#define int long long

int cnt[26];

signed main()
{
    int n;
    string s;
    cin >> n >> s;

    string res = "";
    int ok = 0;
    for (int i = 0; i < n; i++)
    {
        cnt[s[i] - 'a']++;
        if (cnt[s[i] - 'a'] == 5 and ok == 0)
        {
            ok = 1;
            res += string(5, s[i]);
            for (int j = 0; j < 26; j++)
                cnt[j] = 0;
        }
        else if (cnt[s[i] - 'a'] == 7 and ok == 1)
        {
            ok = 2;
            res += string(7, s[i]);
            for (int j = 0; j < 26; j++)
                cnt[j] = 0;
        }
        else if (cnt[s[i] - 'a'] == 5 and ok == 2)
        {
            ok = 3;
            res += string(5, s[i]);
            break;
        }
    }
    if (ok == 3)
        cout << res << endl;
    else
        cout << "none" << endl;
    return 0;
}

F. 集合之和

刚开始看这道题的时候感觉这道肯定是个签到提,但是这个题我们当时都犯浑了,一直在想着怎么找规律,但找的规律都不对,一开始发现了所有奇数都可以构造出来,答案是1 2 3...。然后去想怎么构造偶数的,但发现2和4都构造不出来,是不是有其他偶数也构造不出来,然后去尝试6,8,10…,等等,就这样过了一个多小时还没写出来,但是都有点崩溃了,我当时内心都已经不能平静下去了,但已经过了两三百人了,自己不可能写不出来吧,然后队友构造出来了偶数8的构造为1 2 3 5,然后我就想着看看以这个为突破口,然后突然发现它和奇数的规律好像,都是把最后一位加了1,然后我就去测试10,发现就是这样,当时激动的快哭了。

1 2 3 4

2 3 4 5 6 7 8

1 2 3 5

2 3 4 5 6 7 8 10

然后交了一发A了。激动坏了。差点银牌都没了,就卡在这一道签到题上了。

比赛时AC代码

#include 
using namespace std;
#define int long long

signed main()
{
    int n;
    cin >> n;
    if (n & 1)
    {
        int m = (n + 1) / 2;
        cout << m << endl;
        for (int i = 0; i < m; i++)
        {
            cout << i << " ";
        }
        cout << endl;
    }
    else
    {
        if (n == 2 or n == 4)
            cout << -1 << endl;
        else
        {
            int m = n / 2;
            cout << m << endl;
            for (int i = 1; i < m; i++)
            {
                cout << i << " ";
            }
            cout << m + 1 << endl;
        }
    }
    return 0;
}

G. Mocha 上大班啦

这道题也是签到题,队长先发现了这道题,看过的人也挺多,然后发现和概率有关,顿时就犯了难,因为关于概率的问题都特别难。但是当时已经过了几十个人了,就想着不可能太难。最后发现概率是个幌子,一点没用。这道题和概率没有任何关系。纯粹是迷惑人的。最后队长一发A了。不得不说这题真是妙啊。

思路:枚举

题目的本意是将n个字符串想与,最后统计字符串中有多少个1,直接枚举即可。

比赛时AC代码

#include 
using namespace std;
#define int long long

string s[1010];
int cnt[4010];
signed main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; i++)
    {
        cin >> s[i];
        for (int j = 1; j <= m; j++)
        {
            if (s[i][j - 1] == '1')
                cnt[j]++;
        }
    }

    int q;
    cin >> q;
    while (q--)
    {
        int a, b, l, r, p;
        cin >> a >> b >> l >> r >> p;
    }

    int res = 0;
    for (int i = 1; i <= m; i++)
    {
        if (cnt[i] == n)
            res++;
    }
    cout << res << endl;

    return 0;
}

H. 旋转水管

这题是队长首先看到的,我俩都觉得这题不难,肯定能写,但当时只有一个人过,并且很多人都wa了,心想不可能这么难吧,然后就开始写,首先想的是Acwing里的AcWing 1131. 拯救大兵瑞恩这道题,想着还记录状态,但写完了之后提交wa了,然后发现光记录每个格子的状态有没有经历过不行,因为每个水管必须只能更改一次方向,而且只能走一次,所以不能记录状态,然后队长重写了一遍,但越来越复杂,写了四百多行,最后提交还是wa了,然后我突然想到bfs不行,拿dfs可不可以,然后计算了一下复杂度,最后发现由于水管的特殊形态,所以最多只有几种走法,大约是O(n)的复杂度,所以一定不会超时,然后我就提醒队长让他用dfs写,然后十分钟不到就写完并提交A了,我们当时贼激动,太艰难了,终究是过了,一下上到银牌了。

思路:DFS

每次搜的时候记录每个位置有没有走过,如果走过就不能在走,如果出界了也就不能在走了。走完之后还要回溯回来,为了换个路径寻找。

  • 遇到I:只能从上一个过来的方向直走
  • 遇到L: 从上一个过来的方向向它的两边走

比赛时AC代码

#include 
using namespace std;
#define int long long

const int N = 1e5 + 10;
char g[3][N];
bool st[3][N];
int n = 4, m, ex, ey;
// 1 是往下走,2是往左走,3是往上走,4是往右走
bool dfs(int x, int y, int k)
{
    if (x == 3 and y == ey)
        return true;
    if (x < 1 or x > 2 or y < 1 or y > m or st[x][y])
        return false;
    st[x][y] = true;
    bool t;
    if (g[x][y] == 'I')
    {
        if (k == 1)
            t = dfs(x + 1, y, 1);
        else if (k == 2)
            t = dfs(x, y - 1, 2);
        else if (k == 3)
            t = dfs(x - 1, y, 3);
        else
            t = dfs(x, y + 1, 4);
    }
    else
    {
        if (k == 1 or k == 3)
        {
            t = (dfs(x, y - 1, 2) || dfs(x, y + 1, 4));
        }
        else if (k == 2 or k == 4)
        {
            t = (dfs(x - 1, y, 3) || dfs(x + 1, y, 1));
        }
    }
    st[x][y] = false;
    return t;
}

void solve()
{
    cin >> m >> ex >> ey;
    for (int i = 1; i <= 2; i++)
    {
        string s;
        cin >> s;
        for (int j = 1; j <= m; j++)
        {
            st[i][j] = false;
            g[i][j] = s[j - 1];
        }
    }

    if (dfs(1, ex, 1))
        cout << "YES" << endl;
    else
        cout << "NO" << endl;
}

signed main()
{
    freopen("in.in", "r", stdin);
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;

    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

比赛的时候只写了这五道题,剩下的能补的尽快补上。

你可能感兴趣的:(算法题解,算法,深度优先,c++,1024程序员节)