1. 程式人生 > 其它 >AtCoder Beginner Contest 248 賽時記錄

AtCoder Beginner Contest 248 賽時記錄

目錄

手速場。手速場。手速場。手速場。手速場。

上大分。上大分。上大分。上大分。上大分。

A - Lacked Number

隨便標記看看哪個數沒出現過,或者拿 \(45\) 去把所有數減掉剩下的數就是。

B - Slimes

暴力乘,算次數,做完了。

C - Dice Sum

簡單 DP。

\(f_{i,j}\) 表示前 \(i\) 個數的和為 \(j\) 的方案數。

\[f_{i,j} = \sum_{k=1}^{m} f_{i-1,j-k} \]

D - Range Count Query

對每個顏色開一個 vector,然後存出現的位置。

對於每次詢問直接在對應 vectorupper_bound 出和合法的左右端點相減就能得到答案。

signed main() {
    n = read();
    for(int i = 1; i <= n; ++i) {
        a[i] = read();
        b[a[i]].push_back(i);
    }
    Q = read();
    for(int i = 1, l, r, x; i <= Q; ++i) {
        l = read(), r = read(), x = read();
        int L = upper_bound(b[x].begin(), b[x].end(), l - 1) - b[x].begin() - 1;
        int R = upper_bound(b[x].begin(), b[x].end(), r) - b[x].begin() - 1;
        cout << R - L << "\n";
    }
	return 0;
}

E - K-colinear Line

列舉兩個點確定一條直線,然後列舉第三個點判斷有多少點在這個直線上。

判斷直線的方式我們採用向量的形式,\(i,j,k\) 三個點可以得到兩個向量 \((a,b) = (x_i-x_k,y_i-y_k), (c,d) = (x_j-x_k,y_j-y_k)\),那如果 \(ad=bc\) 就說明這三個點在一條直線上。

然後發現這樣會算重很多。

對於一條有 \(K\) 個點的直線來說,會被算重 \(\frac{K(K-1)}{2}\),所以統計 \(K\) 個點的直線有幾條,計算貢獻的時候除以 \(\frac{K(K-1)}{2}\) 就好了。

bool Check(int i, int j, int k) {
    int ax = x[i] - x[k], ay = y[i] - y[k];
    int bx = x[j] - x[k], by = y[j] - y[k];
    return ax * by == ay * bx;
}

signed main() {
    n = read(), K = read();
    if(K == 1) { return puts("Infinity"), 0; }
    for(int i = 1; i <= n; ++i) x[i] = read(), y[i] = read();
    for(int i = 1; i <= n; ++i) {
        for(int j = i + 1; j <= n; ++j) {
            int res = 2;
            for(int k = 1; k <= n; ++k) {
                if(k == i || k == j) continue;
                if(Check(i, j, k)) res ++;
            }
            cnt[res] ++;
        }
    }
    for(int i = K; i <= n; ++i) ans += cnt[i] * 2 / i / (i - 1);
    cout << ans << "\n";
	return 0;
}

F - Keep Connect

考慮直接 DP。

一開始的一個想法是設 \(f_{i,j,0/1}\) 表示前 \(i\) 列刪了 \(j\) 條邊第 \(i\) 列中間那條邊刪沒刪,然後發現你轉移的時候不知道最後的結果合不合法,因為不知道連通性,所以把意義換一下,改成表示前 \(i\) 列刪了 \(j\) 條邊是否聯通的方案數。

然後在打草紙上畫一下所有情況進行轉移即可。

最後可以得出:

初始化 \(f_{1,0,1} = f_{1,1,0} = 1\)

轉移方程為:

\[\begin{aligned} f_{i,j,1} & = f_{i-1,j,1} + 3 f_{i-1,j-1,1} + f_{i-1,j,0} \\ f_{i,j,0} & = f_{i-1,j-1,0} + 2 f_{i-1,j-2,1} \end{aligned} \]

答案就是 \(f_{n,i,1}\)

signed main() {
    n = read(), P = read();
    f[1][0][1] = 1, f[1][1][0] = 1;
    for(int i = 1; i <= n; ++i) {
        for(int j = 0; j <= n - 1; ++j) {
            f[i][j][1] += f[i - 1][j][1];
            if(j > 0) f[i][j][1] += f[i - 1][j - 1][1] * 3;
            f[i][j][1] += f[i - 1][j][0];
            if(j > 0) f[i][j][0] += f[i - 1][j - 1][0];
            if(j > 1) f[i][j][0] += f[i - 1][j - 2][1] * 2;
            f[i][j][1] %= P, f[i][j][0] %= P;
        }
    }
    for(int i = 1; i <= n - 1; ++i) {
        cout << f[n][i][1] << " ";
    }
	return 0;
}