【CodeForces】CodeForces Round #460 (Div. 2) 題解
阿新 • • 發佈:2018-12-24
【比賽連結】
【題解連結】
【A】Supermarket
【思路要點】
- 選取單價最低的店進行購買。
- 時間複雜度\(O(N)\)。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 5005; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int main() { int n, m; read(n), read(m); double ans = 1e99; for (int i = 1; i <= n; i++) { double x, y; read(x), read(y); ans = min(ans, m * x / y); } printf("%.10lf\n", ans); return 0; }
【B】Perfect Number
【思路要點】
- 列舉答案,暴力判斷是否為Perfect Number即可。
- 時間複雜度\(O(AnsLogAns))\)。
- 本題可以採用列舉位數和第一個數字的方式做到更優秀的複雜度。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 5005; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int main() { int n, ans = 0; read(n); while (n != 0) { ans++; int tmp = ans, sum = 0; while (tmp) { sum += tmp % 10; tmp /= 10; } if (sum == 10) n--; } writeln(ans); return 0; }
【C】Seat Arrangements
【思路要點】
- 對每一行與每一列分別掃描,計算出每一段極長的連續空位的長度,以此來計算答案即可。
- 注意對\(k=1\)的情況單獨處理。
- 時間複雜度\(O(N*M)\)。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2005; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } char a[MAXN][MAXN]; int main() { int n, m, k, ans = 0; read(n), read(m), read(k); for (int i = 1; i <= n; i++) scanf("\n%s", a[i] + 1); if (k == 1) { for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) if (a[i][j] == '.') ans++; writeln(ans); return 0; } for (int i = 1; i <= n; i++) { int now = 0; for (int j = 1; j <= m + 1; j++) if (a[i][j] == '.') now++; else { if (now >= k) ans += now - k + 1; now = 0; } } for (int j = 1; j <= m; j++) { int now = 0; for (int i = 1; i <= n + 1; i++) if (a[i][j] == '.') now++; else { if (now >= k) ans += now - k + 1; now = 0; } } writeln(ans); return 0; }
【D】Substring
【思路要點】
- 首先,當且僅當圖中存在環時,答案為-1,因此首先DFS判斷是否有環。
- 由於問題是求最大值的最大值,因此我們可以將每一個字母分開計算,取最大值。
- 有向無環圖上的最長路徑我們可以用一個簡單DP在\(O(N+M)\)的時間內求解。
- 因此,總時間複雜度為\(O(|S|*(N+M))\),本題中\(|S|=26\)。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 300005; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } char s[MAXN], now; int ans[MAXN]; vector <int> a[MAXN]; bool vis[MAXN], ins[MAXN], halted; void chkmax(int &x, int y) { x = max(x, y); } int get(int pos) { if (ans[pos] != -1) return ans[pos]; int tans = 0; for (unsigned i = 0; i < a[pos].size(); i++) chkmax(tans, get(a[pos][i])); return ans[pos] = tans + (now == s[pos]); } void visit(int pos) { if (vis[pos]) return; if (ins[pos]) { halted = true; return; } ins[pos] = true; for (unsigned i = 0; i < a[pos].size(); i++) visit(a[pos][i]); ins[pos] = false; vis[pos] = true; } int main() { int n, m; read(n), read(m); scanf("\n%s", s + 1); for (int i = 1; i <= m; i++) { int x, y; read(x), read(y); a[x].push_back(y); } for (int i = 1; i <= n; i++) visit(i); if (halted) { printf("-1\n"); return 0; } int Max = 0; for (now = 'a'; now <= 'z'; now++) { memset(ans, -1, sizeof(ans)); for (int i = 1; i <= n; i++) chkmax(Max, get(i)); } writeln(Max); return 0; }
【E】Congruence Equation
【思路要點】
首先,\(P\)是質數,所以,\(a^{P-1}\equiv 1(Mod\ P)(a=1,2,...,P-1)\)。
- \(n*a^{n}\equiv b(Mod P)\Leftrightarrow n\equiv b*a^{-n}(Mod\ P)\)。
- 等式的左側是一個週期為\(P\)的數列,而等式的右側是一個週期為\(P-1\)的數列。
- 可以證明,二元組\((i\ Mod\ P,b*a^{-i}\ Mod\ P)(i\in N^{+})\)以\(P*(P-1)\)為一個週期,且一個週期內每一個二元組恰好出現一次。
- 因此,我們列舉可能對答案產生貢獻的(即兩項相等的)\(P-1\)個二元組,計算其第一次出現時\(i\)的取值,並統計對答案的貢獻即可。
- 時間複雜度\(O(P)\)。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1000005; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } long long a, b, P, x; long long inv[MAXN], val[MAXN]; int main() { read(a), read(b), read(P), read(x); inv[1] = 1; for (int i = 2; i <= P - 1; i++) { long long q = P / i, r = P % i; inv[i] = (P - q) * inv[r] % P; } val[0] = 1; for (int i = 1; i <= P - 1; i++) val[i] = val[i - 1] * a % P; for (int i = 1; i <= P - 1; i++) val[i] = b * inv[val[i]] % P; long long ans = 0; for (int i = 1; i <= P - 1; i++) { long long tmp = i + (P - 1) * ((i + P - val[i]) % P); if (tmp <= x) ans += 1 + (x - tmp) / (P * (P - 1)); } writeln(ans); return 0; }
【F】A Game With Numbers
【思路要點】
- 每個玩家本質不同的手牌集合共有\(\binom{12}{4}=495\)種,因此本質不同的局面數共有\(2*495^{2}=490050\)種(算上玩家的先後手)。
- 將遊戲圖構建出來(每個點出度不會超過16,因此遊戲圖的大小是可以接受的),並標明遊戲結束狀態的勝負性。
- 反向儲存遊戲圖的邊,並且維護每個點在原圖中的出度。
- 將已經確定勝負性的狀態放入佇列中,依次掃描。將在新圖中被一個必敗態的節點指向的點標為必勝態,若它還沒有被加入佇列,就將其加入佇列;將在新圖中被一個必勝態的節點指向的點在原圖中的出度減1,若出度減少到0,且它還沒有被加入佇列,就將其標為必敗態,並加入佇列。
- 這個過程確定了所有必勝和必敗態節點的勝負性,其餘的節點則為平局態。
- 時間複雜度\(O(M+T)\),其中\(M\)為遊戲圖的邊數。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXM = 1 << 25; const int MAXN = 490055; const int MAXS = 1 << 12; template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct info {int cnt[5]; }; int hash(info a) { int ans = 0, now = -1; for (int i = 0; i <= 3; i++) { now += 1 + a.cnt[i]; ans |= 1 << now; } return ans; } info decode(int x) { info ans; int now = 0, pos = 0; for (int i = 1, j = 1; i <= 12; i++, j <<= 1) if (x & j) ans.cnt[pos++] = now, now = 0; else now++; ans.cnt[pos] = now; return ans; } int cnt, num[MAXM]; int d[MAXN], bits[MAXS]; bool vis[MAXN], win[MAXN]; vector <int> a[MAXN]; int l, r, q[MAXN]; int main() { for (int i = 0; i < MAXS; i++) { int ans = 0, tmp = i; while (tmp) { ans += tmp & 1; tmp >>= 1; } bits[i] = ans; } for (int t = 0; t <= 1; t++) for (int i = 0; i < MAXS; i++) { if (bits[i] != 4) continue; for (int j = 0; j < MAXS; j++) { if (bits[j] != 4) continue; int S = (t << 24) + (i << 12) + j; num[S] = ++cnt; } } for (int t = 0; t <= 1; t++) for (int i = 0; i < MAXS; i++) { if (bits[i] != 4) continue; info fi = decode(i); for (int j = 0; j < MAXS; j++) { if (bits[j] != 4) continue; info fj = decode(j); int S = num[(t << 24) + (i << 12) + j]; if (t == 0) { for (int ti = 1; ti <= 4; ti++) { if (fi.cnt[ti] == 0) continue; for (int tj = 1; tj <= 4; tj++) { if (fj.cnt[tj] == 0) continue; int res = (ti + tj) % 5; fi.cnt[ti]--, fi.cnt[res]++; int T = num[((t ^ 1) << 24) + (hash(fi) << 12) + j]; d[S]++, a[T].push_back(S); fi.cnt[ti]++, fi.cnt[res]--; } } } else { for (int ti = 1; ti <= 4; ti++) { if (fi.cnt[ti] == 0) continue; for (int tj = 1; tj <= 4; tj++) { if (fj.cnt[tj] == 0) continue; int res = (ti + tj) % 5; fj.cnt[tj]--, fj.cnt[res]++; int T = num[((t ^ 1) << 24) + (i << 12) + hash(fj)]; d[S]++, a[T].push_back(S); fj.cnt[tj]++, fj.cnt[res]--; } } } } } l = 0, r = -1; for (int t = 0; t <= 1; t++) for (int i = 0; i < MAXS; i++) { if (bits[i] != 4) continue; for (int j = 0; j < MAXS; j++) { if (bits[j] != 4) continue; int S = num[(t << 24) + (i << 12) + j]; if (i == 3840) { vis[S] = true; win[S] = t ^ 1; q[++r] = S; } else if (j == 3840) { vis[S] = true; win[S] = t; q[++r] = S; } } } while (l <= r) { int tmp = q[l++]; if (win[tmp]) { for (unsigned i = 0; i < a[tmp].size(); i++) { d[a[tmp][i]]--; if (!vis[a[tmp][i]] && d[a[tmp][i]] == 0) { vis[a[tmp][i]] = true; win[a[tmp][i]] = false; q[++r] = a[tmp][i]; } } } else { for (unsigned i = 0; i < a[tmp].size(); i++) { if (!vis[a[tmp][i]]) { vis[a[tmp][i]] = true; win[a[tmp][i]] = true; q[++r] = a[tmp][i]; } } } } int T; read(T); while (T--) { int s, tmp; read(s); tmp = s; info a, b; memset(a.cnt, 0, sizeof(a.cnt)); memset(b.cnt, 0, sizeof(b.cnt)); for (int i = 1; i <= 8; i++) { int x; read(x); a.cnt[x]++; } for (int i = 1; i <= 8; i++) { int x; read(x); b.cnt[x]++; } s <<= 12; s += hash(a); s <<= 12; s += hash(b); s = num[s]; if (vis[s]) { if (win[s] ^ tmp) printf("Alice\n"); else printf("Bob\n"); } else printf("Deal\n"); } return 0; }