APCS 2020-10 題解

💡Hint:程式碼省略最前面巨集部分,可以在 About 頁面找到。

p1. 人力分配

題目連結

Solution

直接枚舉工廠一員工數量 $0 \sim n$,挑出最大收益的。時間複雜度 $O(n)$。

AC code

int f(int a, int b, int c, int x) {
    return a*x*x + b*x + c;
}

signed main() {
    hyper;
    int a1, b1, c1, a2, b2, c2, n;
    cin >> a1 >> b1 >> c1 >> a2 >> b2 >> c2 >> n;
    int ans = -INF;
    rep1(i,0,n) {
        int j = n-i;
        ans = max(ans, f(a1,b1,c1,i) + f(a2,b2,c2,j));
    }
    cout << ans << '\n';
}

p2. 人口遷移

題目連結

Solution

就…直接模擬,注意人口遷移的時候不能直接在同一個陣列上面做,先把每個城市移入移出人數都算好再一起加回原本陣列就好。時間複雜度 $O(mRC)$。

AC code

int r, c, k, m;
int a[55][55];
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};

signed main() {
    hyper;
    cin >> r >> c >> k >> m;
    rr(a, -1);
    rep1(i,1,r) rep1(j,1,c) cin >> a[i][j];
    while(m--) {
        int b[55][55] = {0};
        rep1(i,1,r) rep1(j,1,c) {
            int s = a[i][j] / k;
            rep(t,0,4) {
                int x = i+dx[t], y = j+dy[t];
                if(a[x][y] == -1) continue;
                b[x][y] += s, a[i][j] -= s;
            }
        }
        rep1(i,1,r) rep1(j,1,c) a[i][j] += b[i][j];
    }
    int mx = -INF, mn = INF;
    rep1(i,1,r) rep1(j,1,c) {
        mx = max(mx, a[i][j]);
        if(a[i][j] != -1) mn = min(mn, a[i][j]);
    }
    cout << mn << '\n' << mx << '\n';
}

p3. 勇者修煉

題目連結

Solution

如果只能往右下移動的話就變成簡單的 dp 了,只要從左邊跟上面選大的,再加上這格的經驗值就是這格的答案。利用這個想法,因為不能重複走,所以可以把往右下移動跟左下移動分開算,並在由上往下轉移的時候從這兩種選較大的就好。具體轉移式如下 $$ dpl[i][j] = \max(dpl[i][j-1],\, \max(dpl[i-1][j],\, dpr[i-1][j])) + a[i][j] $$ $dpr$ 同理,另外答案可能是負值,要注意邊界條件。時間複雜度 $O(mn)$。

AC code

int m, n, a[55][MN];
int dpl[55][MN], dpr[55][MN];

signed main() {
    hyper;
    cin >> m >> n;
    rep1(i,1,m) rep1(j,1,n) cin >> a[i][j];
    rep1(i,1,m) dpl[i][0] = dpr[i][n+1] = -INF;
    rep1(i,1,m) {
        rep1(j,1,n) dpl[i][j] = max(dpl[i][j-1], max(dpl[i-1][j], dpr[i-1][j])) + a[i][j];
        for(int j=n; j>=1; --j) dpr[i][j] = max(dpr[i][j+1], max(dpl[i-1][j], dpr[i-1][j])) + a[i][j];
    }
    int ans = -INF;
    rep1(j,1,n) ans = max(ans, max(dpl[m][j], dpr[m][j]));
    cout << ans << '\n';
}

p4. 低地距離

題目連結

Solution 1

把陣列的數字分成 $A = \{x \mid x \le \lfloor \frac{n}{2} \rfloor\}$ 與 $B = \{x \mid x > \lfloor \frac{n}{2} \rfloor\}$ 兩個部分分別下去做分治,合併時只需要計算每一對 $B$ 裡的數字中間夾了幾個 $A$ 裡的數字。要計算這個,我們只需要在掃過陣列時紀錄一個前綴和 $ps$,遇到 $x \in A$ 就把 $ps + 1$,第一次遇到 $x \in B$ 就把 $ans - ps$,第二次遇到就把 $ans + ps$。時間複雜度 $O(n \log n)$。

AC code

int solve(vector<int> a) {
    int n = a.size() / 2;
    if(n <= 1) return 0;
    int m = n / 2;
    vector<int> x, y;
    int ans = 0, ps = 0;
    bool vis[m+2] = {0};
    for(int t: a) {
        if(t <= m) {
            x.push_back(t);
            ps++;
        } else {
            y.push_back(t-m);
            if(vis[t-m]) ans += ps;
            else ans -= ps, vis[t-m] = 1;
        }
    }
    return solve(x) + solve(y) + ans;
}

signed main() {
    hyper;
    int n, x;
    vector<int> a;
    cin >> n;
    rep(i,0,n*2) {
        cin >> x;
        a.push_back(x);
    }
    cout << solve(a) << '\n';
}

Solution 2

可以從小數字的開始往上算,並維護一個陣列 $A[2n]$ 紀錄目前處理完的數字,初始化為 $0$。每次算完某一對數字就把 $A$ 中相對應的兩個位置設成 $1$ ,這樣在算 $k$ 的時候可以確保 $A$ 中已經記錄了所有 $< k$ 的數字,數字 $k$ 夾住的那個區間和就是 $k$ 的低窪值。所以它其實是單點加值、區間和查詢,可以用線段樹或 BIT 實作。

struct Fenwick {
    vector<int> v;
    int size;
    Fenwick(int n) {
        v.resize(n+2, 0);
        size = n+1;
    }
    int lowbit(int x) { return x & (-x); }
    void modify(int pos, int x) {
        for(int i=pos; i<=size; i+=lowbit(i)) {
            v[i] += x;
        }
    }
    int query(int pos) {
        int sum = 0;
        for(int i=pos; i>0; i-=lowbit(i)) {
            sum += v[i];
        }
        return sum;
    }
    int rsum(int l, int r) {
        return query(r) - query(l-1);
    }
};

signed main() {
    hyper;
    int n, l[MN], r[MN];
    cin >> n;
    Fenwick bit(n*2);
    rep1(i,1,n*2) {
        int x;
        cin >> x;
        if(l[x] == 0) l[x] = i;
        else r[x] = i;
    }
    int ans = 0;
    rep1(i,1,n) {
        ans += bit.rsum(l[i], r[i]);
        bit.modify(l[i], 1);
        bit.modify(r[i], 1);
    }
    cout << ans << '\n';
}
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus