【解題報告】Educational Codeforces Round 16

題目鏈接


A. King Moves

思路

根據棋盤的特點可以分類討論:

  • 當王在棋盤的角落上時,王有 3 種走法。
  • 當王在棋盤的邊緣上時,王有 5 種走法。
  • 其它情況,王有 8 種走法

代碼

#include <bits/stdc++.h>
using namespace std;

string s;

int main() {
    cin >> s;
    if(s == "a1" || s == "h1" || s == "a8" || s == "h8") {
        cout << 3;
    }
    else if(s[0] == 'a' || s[0] == 'h' || s[1] == '1' || s[1] == '8') {
        cout << 5;
    }
    else {
        cout << 8;
    }
    cout << endl;
    return 0;
}

B. Optimal Point on a Line

思路

樸素的思想中,枚舉最優點,然後計算所有點到這個點的距離之和就能解決問題。但是 O(n2) 的時間複雜度是無法勝任本題的數據規模的。

接下來考慮讓點有序是否對解題會有幫助,假設現在的點是按照座標的大小從小到大排列的。考慮當我們知道了第 i 個點到所有點的距離之和 sum(i) 後,能否知道第 i+1 個點到所有點的距離之和 sum(i+1) 。我們規定 less(i) 爲比 i 座標小的所有點的集合, dis(i,j) 爲點 i 到點 j 的距離(可以用前綴和預數組處理出來)。那麼點 i+1 到點集 less(i+1) 中每點的距離之和與點 i 到點集 less(i+1) 中每點的距離之和的差 sub(i)less(i+1) 的點數乘 dis(i,i+1)

於是在算出了 sum(i) ,以後,我們就可以根據 sub(i) 求得 sum(i+1) ,從而從 sum(1) 遞推到 sum(n) 。問題就在 O(n) 的複雜度下圓滿地解決了。

代碼

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 3e5 + 5;
int n, x;
ll sum, ans, a[maxn];

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%I64d", &a[i]);
    }
    sort(a + 1, a + n + 1);
    for(int i = 2; i <= n; i++) {
        sum += a[i] - a[1];
    }
    ans = sum;
    x = a[1];
    for(int i = 2; i <= n; i++) {
        sum += (i + i - n - 2) * (a[i] - a[i-1]);
        if(sum < ans) {
            ans = sum;
            x = a[i];
        }
    }
    printf("%d\n", x);
    return 0;
}

C. Magic Odd Square

思路

奇數階幻方的幻和恰好也是奇數,於是問題就轉化成了如何構造奇數階幻方。(關於幻方,幻和和奇數階幻方的構造,進入這個鏈接瞭解更多)

這裏寫圖片描述

代碼

#include <bits/stdc++.h>
using namespace std;

const int maxn = 50;
int n, x, y, tx, ty, G[maxn][maxn];

int main() {
    scanf("%d", &n);
    x = 0;
    y = n / 2;
    for(int i = 1; i <= n * n; i++) {
        G[x][y] = i;
        tx = (x - 1 + n) % n;
        ty = (y + 1) % n;
        if(G[tx][ty] > 0) {
            x++;
            continue;
        }
        x = tx;
        y = ty;
    }
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            printf("%d ", G[i][j]);
        }
        puts("");
    }
    return 0;
}

E. Generate a String

思路

原本的思路是,因爲狀態 i (生成 ia )能從狀態 i+1 轉移過來,所以用動態規劃不好解決。但是用最短路可以解決。囿於題給的數據量,我沒能在比賽中正確解決這個問題,最後以 MLE 告終(也有人說剪枝後能用最短路解決)。

下面說明正確的解法:

  • i 爲奇數時,狀態 i 從狀態 i1i+12 轉移過來是最優的。爲什麼是 i+12 而不是 i+32 或者數值更大的狀態呢?因爲從 i+32 轉移過來不如先從 i+32 轉移到 i+321 再轉移到 2×(i+321) ,即 i+1 ,這樣轉移到 i 的花費會更少。最後狀態轉移方程就是 d[i]=min(d[i1]+x,d[(i+1)/2]+x+y)
  • i 爲偶數時,狀態 i 從狀態 i1i2 轉移過來是最優的。爲什麼是 i2 而不是 i+22 或數值更大的狀態呢?答案跟奇數的情形是類似的,這裏就不贅述了。最後狀態轉移方程就是 d[i]=min(d[i1]+x,d[i/2]+y)

代碼

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e7 + 5;
int n, x, y;
ll d[maxn];

int main() {
    cin >> n >> x >> y;
    for(int i = 1; i <= n; i++) {
        if(i % 2) {
            d[i] = min(d[i-1] + x, d[(i+1)/2] + x + y);
        }
        else {
            d[i] = min(d[i-1] + x, d[i/2] + y);
        }
    }
    cout << d[n] << endl;
    return 0;
}

(其它題目略)

發佈了70 篇原創文章 · 獲贊 30 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章