2018年湘潭大学程序设计竞赛 - 题解

湘潭大学的校赛对ACM新手的考察还是很全面很合理的,题目不难,多掌握些知识就可以都做出来。

题目链接:点这儿

A - 时间统计

给你一个开始时间和结束时间,让你算一下这中间经过了多少秒。

这题是个签到题,模拟下减法就行了,注意代码的简洁写法。

#include <bits/stdc++.h>

using namespace std;

int main()
{
    for (int T; EOF != scanf("%d", &T); ) {
        for (int d[2], h[2], m[2], s[2]; T--; ) {
            for (int i = 0; i < 2; i++)
                scanf("%dday%d:%d:%d", &d[i], &h[i], &m[i], &s[i]);
            printf("%d\n", (d[1] - d[0]) * 60 * 60 * 24 +
                            (h[1] - h[0]) * 60 * 60 +
                            (m[1] - m[0]) * 60 +
                            s[1] - s[0]);
        }
    }
    return 0;
}

B - String

换个角度看这个题,代码量会减少很多。

str中的字符在mp中查找,然后在对应的行列上++,最后按照按行优先的方式去遍历行列,输出就行。

#include <bits/stdc++.h>

using namespace std;

const char mp[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

int main()
{
    int T;
    for (scanf("%d", &T); T--; ) {
        char str[1 << 9];
        scanf("%s", str);
        int r[6] = {0}, c[6] = {0};
        for (int i = 0; str[i]; ++i) {
            int sum = 0;
            for (; mp[sum] && mp[sum] != str[i]; ++sum) {}
            ++r[sum / 6];
            ++c[sum % 6];
        }
        int max_r = *max_element(r, r + 6);
        int max_c = *max_element(c, c + 6);
        for (int i = 0; i < 6; i++)
            for (int j = 0; j < 6; j++)
                if (r[i] == max_r && c[j] == max_c)
                    putchar(mp[i * 6 + j]);
        puts("");
    }
    return 0;
}

C - Boom

这题数据方位不大,于是暴力就行,开一个数组,对于爆炸区域中的每一个格子都++,最后维护一个最大值就行了,注意题中的不考虑边界和角落在代码中的体现。

这题如果数据范围大了还要进行离散化然后二维树状数组维护。这里提一下。

#include <bits/stdc++.h>

using namespace std;

#define MAX_SIZE 105

int main()
{
    int T;
    for (scanf("%d", &T); T--; ) {
        int n;
        scanf("%d", &n);
        int mp[MAX_SIZE * MAX_SIZE] = {0};
        for (int i = 0, x1, y1, x2, y2; i < n; i++) {
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            for (int ii = x1 + 1; ii <= x2; ++ii)
                for (int jj = y1 + 1; jj <= y2; ++jj)
                    ++mp[ii * MAX_SIZE + jj];
        }
        printf("%d\n", *max_element(mp, mp + MAX_SIZE * MAX_SIZE));
    }
    return 0;
}

D - Fibonacci进制

先凑出最大的那个二进制,然后利用100可以转化成011把最大的二进制逐步变成最小的二进制就行了。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

int f[44];

int main()
{
    f[0] = 1, f[1] = 2;
    for (int i = 2; i < 44; f[i] = f[i - 1] + f[i - 2], ++i) {}

    int T, n;
    for (scanf("%d", &T); T--; ) {
        scanf("%d", &n);
        LL ans = 0;
        for (unsigned int bit; n; n -= f[bit - 1]) {
            bit = lower_bound(f, f + 44, n + 1) - f;
            ans |= 1LL << bit - 1;
        }
        bool f = true;
        while (f) {
            f = false;
            for (int i = 0; 1LL << i <= ans; ++i)
                if (i > 1 && 1LL << i & ans && !(1LL << i - 1 & ans) && !(1LL << i - 2 & ans)) {
                    ans &= ~(1LL << i);
                    ans |= 1LL << i - 1;
                    ans |= 1LL << i - 2;
                    f = true;
                    break;
                }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

E - 吃货

二分找能吃的最后一种食物,然后预处理美味度的最大值。

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int T;
    for (scanf("%d", &T); T--; ) {
        int n, m, t;
        scanf("%d%d", &n, &m);
        vector<pair<int, int> > arr;
        for (int i = 0, x, y; i < n; i++)
            scanf("%d%d", &x, &y), arr.emplace_back(x, y);
        sort(arr.begin(), arr.end());
        vector<int> dp(n);
        dp[0] = arr[0].second;
        for (int i = 1; i < n; dp[i] = max(arr[i].second, dp[i - 1]), ++i) {}

        for (; m--; ) {
            scanf("%d", &t);
            auto it = lower_bound(arr.begin(), arr.end(), make_pair(t + 1, 0)) - arr.begin();
            printf("%d\n", it == 0 ? 0 : dp[it - 1]);
        }
    }
    return 0;
}

F - maze

很明显的广搜,不过要注意下面两点:

  • 用优先队列来加速搜索;
  • 由于一个格子有多个入口,多个出口,于是用multimap映射出入口关系。
#include <bits/stdc++.h>

using namespace std;

const int INF = 0x3f3f3f3f;

const int dirx[] = {0, 0, 1, -1};
const int diry[] = {1, -1, 0, 0};

int main()
{
    for (int n, m, q; EOF != scanf("%d%d%d", &n, &m, &q); ) {
        vector<int> dp(n * m, INF);
        vector<string> mp(n);
        for (int i = 0; i < n; cin >> mp[i++]) {}
        multimap<pair<int, int>, pair<int, int> > traces;
        for (int i = 0, x, y, x2, y2; i < q; i++) {
            cin >> x >> y >> x2 >> y2;
            if (mp[x][y] == '#' || mp[x2][y2] == '#')
                continue;
            traces.insert(make_pair(make_pair(x, y), make_pair(x2, y2)));
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (mp[i][j] == 'S') {
                    priority_queue<pair<int, pair<int, int> >,
                                    vector<pair<int, pair<int, int> > >,
                                    greater<pair<int, pair<int, int> > >
                                    > que;
                    int ans = -1;
                    dp[i * m + j] = 0;
                    que.push(make_pair(0, make_pair(i, j)));
                    while (!que.empty()) {
                        auto now = que.top();
                        que.pop();
                        if (mp[now.second.first][now.second.second] == 'T') {
                            ans = dp[now.second.first * m + now.second.second];
                            break;
                        }
                        for (int k = 0; k < 4; k++) {
                            int tx = now.second.first + dirx[k];
                            int ty = now.second.second + diry[k];
                            if (tx >= 0 && tx < n && ty >= 0 && ty < m && mp[tx][ty] != '#' &&
                                    now.first + 1 < dp[tx * m + ty])
                                dp[tx * m + ty] = now.first + 1,
                                que.push(make_pair(dp[tx * m + ty], make_pair(tx, ty)));
                        }
                        auto s2e = traces.equal_range(now.second);
                        for (auto it = s2e.first; it != s2e.second; ++it) {
                            if (now.first + 3 < dp[it->second.first * m + it->second.second])
                                dp[it->second.first * m + it->second.second] = now.first + 3,
                                que.push(make_pair(now.first + 3, it->second));
                        }
                    }
                    cout << ans << endl;
                    goto F;
                }
            }
        }
        F:;
    }
    return 0;
}

G - 又见斐波那契

这题在博客深入浅出矩阵快速幂及其简单应用中是一个例题,看看这篇博客。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

#define MOD 1000000007LL

#define MAX_N 6

template<typename T, int N = 1>
struct Matrix {
    Matrix(int f = 0) : n(sizeof(data[0]) / sizeof(data[0][0])) {
        memset(data, 0, sizeof(data));
        if (f)
            for (int i = 0; i < n; data[i][i] = 1, ++i) {}
    }

    Matrix operator * (const Matrix& other) const {
        Matrix<T, N> ret;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                for (int k = 0; k < n; k++)
                    ret.data[i][j] = (ret.data[i][j] + data[i][k] * other.data[k][j] % MOD) % MOD;
        return ret;
    }

    Matrix operator + (const Matrix& other) const {
        Matrix<T, N> ret;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                ret.data[i][j] = (data[i][j] + other.data[i][j]) % MOD;
        return ret;
    }

    Matrix& operator % (const Matrix& other) {
        return *this;
    }

    T data[N][N];
    int n;
};

template<typename T>
T mul(T a, LL n, LL mod)
{
    T ret(1);
    for (; n; n >>= 1) {
        ret = ret * (n & 1 ? a : T(1)) % mod;
        a = a * a % mod;
    }
    return ret;
}

const LL modulu[MAX_N][MAX_N] = {
    {1, 1, 1, 1, 1, 1},
    {1, 0, 0, 0, 0, 0},
    {0, 0, 1, 3, 3, 1},
    {0, 0, 0, 1, 2, 1},
    {0, 0, 0, 0, 1, 1},
    {0, 0, 0, 0, 0, 1}
};

int main()
{
    int T;
    cin >> T;
    for (LL n; T--; ) {
        cin >> n;
        if (n <= 1) {
            cout << n << endl;
            continue;
        }
        Matrix<LL, MAX_N> a;
        memcpy(a.data, modulu, sizeof(modulu));
        a = mul(a, n - 1, MOD);
        cout << (a.data[0][0] * 1 + a.data[0][1] * 0 + a.data[0][2] * 8 +
                a.data[0][3] * 4 + a.data[0][4] * 2 + a.data[0][5]) % MOD << endl;
    }
    return 0;
}

H - 统计颜色

线段树,用二进制来存储哪种颜色存在于桶中。

应该算一个裸的线段树模板题。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

#define MAX_SIZE (100000 * 4 + 100)

pair<LL, LL> nodes[MAX_SIZE];
pair<int, int> childs[MAX_SIZE];

int n, m;

void build(int root, int l, int r)
{
    nodes[root].first = nodes[root].second = 0;

    childs[root].first = l;
    childs[root].second = r;
    if (l == r)
        return ;
    build(root << 1, l, (l + r) >> 1);
    build(root << 1 | 1, ((l + r) >> 1) + 1, r);
}

void passLazy(int root)
{
    nodes[root << 1].first |= nodes[root].first;
    nodes[root << 1 | 1].first |= nodes[root].first;

    nodes[root << 1].second |= nodes[root].first;
    nodes[root << 1 | 1].second |= nodes[root].first;

    nodes[root].first = 0;
}

void update(int root, int l, int r, int c)
{
    if (l <= childs[root].first && childs[root].second <= r) {
        nodes[root].second |= 1LL << c;
        nodes[root].first |= 1LL << c;
        return ;
    }
    if (nodes[root].first)
        passLazy(root);
    if (l <= (childs[root].first + childs[root].second) >> 1)
        update(root << 1, l, r, c);
    if (r > (childs[root].first + childs[root].second) >> 1)
        update(root << 1 | 1, l, r,  c);
    nodes[root].second |= nodes[root << 1].second | nodes[root << 1 | 1].second;
}

LL query(int root, int l, int r)
{
    if (l <= childs[root].first && childs[root].second <= r)
        return nodes[root].second;
    if (nodes[root].first)
        passLazy(root);
    LL ret = 0;
    if (l <= (childs[root].first + childs[root].second) >> 1)
        ret |= query(root << 1, l, r);
    if (r > (childs[root].first + childs[root].second) >> 1)
        ret |= query(root << 1 | 1, l, r);
    return ret;
}

int main()
{
    while (EOF != scanf("%d%d", &n, &m)) {
        build(1, 1, n);
        int num, l, r, c;
        for (int i = 0; i < m; i++) {
            scanf("%d%d%d", &num, &l, &r);
            switch (num) {
            case 1:
                scanf("%d", &c);
                update(1, l, r, c);
                break;
            case 2: {
                LL ans = query(1, l, r);
                bitset<64> cnt(ans);
                printf("%d\n", cnt.count());
                break;
            }
            default:
                assert(0);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/FlushHip/article/details/80205444