AtCoder Beginner Contest 248 賽時記錄
阿新 • • 發佈:2022-04-17
目錄
- A - Lacked Number
- B - Slimes
- C - Dice Sum
- D - Range Count Query
- E - K-colinear Line
- F - Keep Connect
手速場。手速場。手速場。手速場。手速場。
上大分。上大分。上大分。上大分。上大分。
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
,然後存出現的位置。
對於每次詢問直接在對應 vector
裡 upper_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;
}