[APCS] 2023年十月場實作題詳解


前言

久違的寫一下題解,最近因為家教的學生有去考所以最近來寫一下題目 因為沒有實際去考,也沒有實際的成績,這邊的測試都是丟到 ZJ 上面的題目

Problem 1: 機械鼠

題目連結

基本上有兩種做法:

  1. 把所有位置讀進來,sort 之後做 lower_bound 掃比他大的跟比他小的有幾個,輸出比較大的順便輸出最前/最後的位置
  2. 讀位置的同時取最大最小值,並且分別紀錄比他大/小的數字有幾個,同時輸出最大/小值

作法一

#include<bits/stdc++.h>

using namespace std;

int main() {
    ios::sync_with_stdio ( false );
    cin.tie ( 0 );
    cout.tie ( 0 );

    int n, x;
    cin >> x >> n;
    vector < int > lib ( n );
    for ( auto &i: lib )
        cin >> i;

    sort ( lib.begin(), lib.end() );
    int lb = lower_bound ( lib.begin(), lib.end(), x ) - lib.begin();
    if ( lb < n - lb )
        cout << n - lb << ' ' << lib.back() << endl;
    else
        cout << lb << ' ' << lib[0] << endl;
}

作法二

#include<bits/stdc++.h>

using namespace std;

int main() {
    ios::sync_with_stdio ( false );
    cin.tie ( 0 );
    cout.tie ( 0 );

    int n, x, ma = -105, mi = 105, cnt1 = 0, cnt2 = 0;
    cin >> x >> n;
    for ( int i = 0, in ; i < n ; i++ ) {
        cin >> in;
        ma = max ( ma, in );
        mi = min ( mi, in );
        if ( in >= x )
            cnt1++;
        if ( in <= x )
            cnt2++;
    }
    if ( cnt1 > cnt2 )
        cout << cnt1 << ' ' << ma << endl;
    else
        cout << cnt2 << ' ' << mi << endl;
}

Problem 2: 卡牌遊戲

題目連結

基本上就是暴力匹配,直到沒有新匹配成立的時候就結束 while 迴圈 每次匹配都往四個方向檢查,要注意的是可能有一個方向檢查到匹配了、把 lib[i][j] 改成 -1 了,就不要再繼續檢查,我為了方便起見寫在後面三個 for 迴圈的條件裡

#include<bits/stdc++.h>

using namespace std;

#define maxN 55

int lib[maxN][maxN];

int main() {
    ios::sync_with_stdio ( false );
    cin.tie ( 0 );
    cout.tie ( 0 );

    int n, m, ans = 0;
    bool flag = true;
    cin >> n >> m;
    for ( int i = 0 ; i < n ; i++ )
        for ( int j = 0 ; j < m ; j++ )
            cin >> lib[i][j];

    while ( flag ) {
        flag = false;
        for ( int i = 0 ; i < n ; i++ )
            for ( int j = 0 ; j < m ; j++ ) {
                if ( lib[i][j] == -1 )
                    continue;

                for ( int k = 1 ; i + k < n ; k++ )
                    if ( lib[i][j] == lib[i + k][j] ) {
                        flag = true;
                        ans += lib[i][j];
                        lib[i][j] = lib[i + k][j] = -1;
                        break;
                    }
                    else if ( lib[i + k][j] != -1 )
                        break;

                for ( int k = 1 ; 0 <= i - k && lib[i][j] != -1 ; k++ )
                    if ( lib[i][j] == lib[i - k][j] ) {
                        flag = true;
                        ans += lib[i][j];
                        lib[i][j] = lib[i - k][j] = -1;
                        break;
                    }
                    else if ( lib[i - k][j] != -1 )
                        break;

                for ( int k = 1 ; j + k < m && lib[i][j] != -1 ; k++ )
                    if ( lib[i][j] == lib[i][j + k] ) {
                        flag = true;
                        ans += lib[i][j];
                        lib[i][j] = lib[i][j + k] = -1;
                        break;
                    }
                    else if ( lib[i][j + k] != -1 )
                        break;

                for ( int k = 1 ; 0 <= j - k && lib[i][j] != -1 ; k++ )
                    if ( lib[i][j] == lib[i][j - k] ) {
                        flag = true;
                        ans += lib[i][j];
                        lib[i][j] = lib[i][j - k] = -1;
                        break;
                    }
                    else if ( lib[i][j - k] != -1 )
                        break;
            }
    }
    cout << ans << endl;
}

Problem 3: 搬家

題目連結

簡單來說就是檢查最大的水管聯通塊,所以寫一個 dfs 或 bfs 掃過去就好 不過要注意兩個相鄰的水管中間有沒有聯通,可能有其中一個方向不對就不聯通了

這邊我是用兩個 function check_dcheck_next,分別檢查當前節點可以轉移的位置、和下一個位置能接受的轉移方向 另外這邊我使用轉移矩陣來檢查,所以這兩個 functino 中的 d 是對照到轉移矩陣的 index

#include<bits/stdc++.h>

using namespace std;

#define maxN 505

char lib[maxN][maxN];
int dx[4] = { 0, 1, 0, -1 }, dy[4] = { 1, 0, -1, 0 };
bool vis[maxN][maxN];

bool check_d ( int x, int y, int d ) {
    if ( lib[x][y] == 'X' )
        return true;
    if ( lib[x][y] == 'I' && d % 2 == 1 )
        return true;
    if ( lib[x][y] == 'H' && d % 2 == 0 )
        return true;
    if ( lib[x][y] == 'L' && ( d == 0 || d == 3 ) )
        return true;
    if ( lib[x][y] == '7' && ( d == 1 || d == 2 ) )
        return true;
    if ( lib[x][y] == 'F' && ( d == 0 || d == 1 ) )
        return true;
    if ( lib[x][y] == 'J' && ( d == 3 || d == 2 ) )
        return true;
    return false;
}

bool check_next ( int x, int y, int d ) {
    if ( lib[x][y] == 'X' )
        return true;
    if ( lib[x][y] == 'I' && d % 2 == 1 )
        return true;
    if ( lib[x][y] == 'H' && d % 2 == 0 )
        return true;
    if ( lib[x][y] == 'L' && ( d == 1 || d == 2 ) )
        return true;
    if ( lib[x][y] == '7' && ( d == 0 || d == 3 ) )
        return true;
    if ( lib[x][y] == 'F' && ( d == 2 || d == 3 ) )
        return true;
    if ( lib[x][y] == 'J' && ( d == 0 || d == 1 ) )
        return true;
    return false;
}

int bfs ( int x, int y ) {
    int nx, ny, res = 1;
    queue < pair < int, int > > q;
    q.push ( make_pair ( x, y ) );
    vis[x][y] = true;
    while ( !q.empty() ) {
        x = q.front().first, y = q.front().second;
        q.pop();
        for ( int d = 0 ; d < 4 ; d++ ) {
            if ( !check_d ( x, y, d ) )
                continue;
            nx = x + dx[d], ny = y + dy[d];
            if ( !check_next ( nx, ny, d ) )
                continue;
            if ( vis[nx][ny] )
                continue;

            vis[nx][ny] = true;
            res++;
            q.push ( make_pair ( nx, ny ) );

        }
    }

    return res;
}

int main() {
    ios::sync_with_stdio ( false );
    cin.tie ( 0 );
    cout.tie ( 0 );

    int n, m, ma = 0;
    cin >> n >> m;
    for ( int i = 0 ; i <= n + 1 ; i++ )
        for ( int j = 0 ; j <= m + 1 ; j++ )
            lib[i][j] = '0';
    for ( int i = 1 ; i <= n ; i++ )
        for ( int j = 1 ; j <= m ; j++ )
            cin >> lib[i][j];


    for ( int i = 1 ; i <= n ; i++ ) {
        for ( int j = 1 ; j <= m ; j++ ) {
            if ( vis[i][j] || lib[i][j] == '0' )
                continue;

            ma = max ( bfs ( i, j ), ma );
        }
    }

    cout << ma << endl;
}

Problem 4: 投資遊戲

題目連結

基本上就是裸 dp

#include<bits/stdc++.h>

using namespace std;

#define maxN 150005
#define maxK 25

long long dp[maxN][maxK], lib[maxN];

int main() {
    ios::sync_with_stdio ( false );
    cin.tie ( 0 );
    cout.tie ( 0 );

    int n, k;
    long long ans;
    cin >> n >> k;
    for ( int i = 0 ; i < n ; i++ )
        cin >> lib[i];

    dp[0][0] = lib[0];
    ans = max ( 0ll, lib[0] );

    for ( int i = 0 ; i < n ; i++ ) {
        ans = max ( ans, dp[i][0] = max ( 0ll, dp[i - 1][0] ) + lib[i] );
        for ( int j = 1 ; j <= k ; j++ ) {
            ans = max ( ans, dp[i][j] = max ( dp[i - 1][j] + lib[i], dp[i - 1][j - 1] ) );
        }
    }

    cout << ans << endl;
}

大概就是這樣,久違的寫個題目,如果有去考應該是可以順利五級分(吧