「牛客 OI 周赛2 – 提高组」解题报告

A – 游戏

我大概乱搞一下:从最外围向内操作,计算操作次数再取模然后对应姓名即可。我不太了解为什么就过了。

// A.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e3 + 200;

char mp[MAX_N][MAX_N];
int n, m, T, delta[MAX_N][MAX_N], now[MAX_N][MAX_N], matrix[MAX_N][MAX_N];

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        memset(delta, 0, sizeof(delta)), memset(now, 0, sizeof(now));
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%s", mp[i] + 1);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                if (mp[i][j] == 'R')
                    matrix[i][j] = 1;
                else if (mp[i][j] == 'G')
                    matrix[i][j] = 2;
                else
                    matrix[i][j] = 0;
        int cnt = 0;
        for (int i = n; i >= 1; i--)
        {
            delta[i][m + 1] += delta[i + 1][m + 1];
            for (int j = m; j >= 1; j--)
            {
                delta[i][j] += delta[i + 1][j];
                now[i][j] = now[i][j + 1] + delta[i][j + 1];
                int curt = (matrix[i][j] + now[i][j]) % 3;
                cnt += (3 - curt) % 3;
                now[i][j] += (3 - curt) % 3, delta[i][j + 1] += (3 - curt) % 3;
            }
        }
        printf("%s\n", cnt % 3 == 2 ? "dreagonm" : (cnt % 3 == 1 ? "fengxunling" : "BLUESKY007"));
    }
    return 0;
}

B – 水果蛋糕

我先打了个表,把\(n \in [3, 6]\)的都打了一遍,然后发现规律;可惜我用了非常丑的写法,打表打废掉了。最后到手只有 20 分。正解如下:

// B.cpp
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

int main()
{
    ll n, m;
    scanf("%lld%lld", &n, &m);
    if (n < m)
        swap(n, m);
    if (m <= 2)
        printf("%lld", n * m);
    else if (m == 3)
        printf("%lld", n + 6 * (n / 6) + 2 * min(n % 6, 3LL));
    else if (m == 4)
    {
        if (n % 6 == 0)
            printf("%lld", 2 * n);
        else if (n % 6 == 1 || n % 6 == 2)
            printf("%lld", 12 * (n / 6) + 4 * (n % 6));
        else if (n % 6 == 3 || n % 6 == 4)
            printf("%lld", 12 * (n / 6) + 4 * 2 + 2 * ((n % 6) - 2));
        else
            printf("%lld", 12 * (n / 6) + 4 * 2 + 2 * 2);
    }
    else
        printf("%lld", (n * m + 1) / 2);
    return 0;
}

C – 好朋友

典型的正难则反系列,刚开始觉得这题比较好做,但是数位 DP 还是不太会处理导致全部炸裂(明天要去做做板子了)。设置状态\(dp[i][j]\)计算长度为\(i\)的、有\(j\)个零的数的个数。防止出现七就行了。具体处理见正解代码:

// C.cpp
#include <bits/stdc++.h>
typedef long long ll;

using namespace std;

ll predigits[20], dp[20][4], T, digits[20];

ll solve(ll pos)
{
    if (pos < 1000)
        return 0;
    int tot = 0, x = 0;
    for (; pos; pos /= 10)
        digits[tot++] = pos % 10;
    reverse(digits, digits + tot);
    memset(dp, 0, sizeof(dp));
    dp[1][0] = digits[0] - 1;
    for (int i = 1; i < tot; i++)
    {
        dp[i + 1][0] = dp[i][0] * 9, dp[i + 1][1] = dp[i][0] + dp[i][1] * 9;
        dp[i + 1][2] = dp[i][1] + dp[i][2] * 9, dp[i + 1][3] = dp[i][2] + dp[i][3] * 10;
        dp[i + 1][x] += digits[i] - 1;
        dp[i + 1][x + ((x < 2 && digits[i]) || (x == 2 && digits[i] > 7))]++;
        if (((x < 2 && !digits[i]) || (x == 2 && digits[i] == 7)))
            x++;
    }
    return predigits[tot - 1] + dp[tot][3];
}

int main()
{
    for (ll i = 0, val = 1; i <= 18; i++, val *= 10)
        predigits[i] = solve(val - 1);
    ll ans = 0;
    scanf("%lld", &T);
    while (T--)
    {
        ll lft, rig;
        scanf("%lld%lld", &lft, &rig);
        ans ^= (solve(rig + 1) - solve(lft));
    }
    printf("%lld", ans);
    return 0;
}

我认为这几场 OI 周赛的题质量不高。

Leave a Reply

Your email address will not be published. Required fields are marked *