AtCoder Beginner Contest 246題解
A - Four Points
題目描述:給你一個矩形的三個頂點座標,問第四個頂點的座標。
思路:根據題意模擬即可。
時間複雜度:\(O(1)\)
參考程式碼:
void solve() {
int x, y, resx = 0, resy = 0;
for (int i = 1; i <= 3; ++i) {
cin >> x >> y;
resx ^= x; resy ^= y;
}
cout << resx << " " << resy << '\n';
return;
}
B - Get Closer
題目描述:告訴你一條經過原點的直線上的一個點,求這條直線上距離原點長度為\(1\)的點的座標。
思路:基礎的計算幾何,若\(x = 0\),直接輸出0 1
,否則先求出斜率\(k\),然後求解:
即可。
時間複雜度:\(O(1)\)
參考程式碼:
void solve() { int x, y; cin >> x >> y; if (x == 0) cout << "0 1" << '\n'; else { double k = y * 1.0 / x; double resx = sqrt(1.0 / (1 + k * k)); double resy = resx * k; cout << setprecision(10) << resx << " " << resy << '\n'; } return; }
C - Coupon
題目描述:你需要買\(n\)種物品,每種物品的價格為\(a_i\),給你\(k\)張優惠卷,優惠卷可以疊加,問你買這\(n\)種物品的最小花費。
思路:比較明顯的貪心,使用優先佇列維護一下當前物品價格的最大值即可。
時間複雜度:\(O(nlogn)\)
參考程式碼:
void solve() { int n, k, x; priority_queue<int> heap; cin >> n >> k >> x; for (int i = 1; i <= n; ++i) { int val; cin >> val; heap.push(val); } while (k != 0 && !heap.empty()) { auto price = heap.top(); heap.pop(); if (price <= x) --k; else { int need = price / x; if (need <= k) k -= need; else need = k, k = 0; price -= need * x; if (price != 0) heap.push(price); } } long long res = 0; while (!heap.empty()) { res += heap.top(); heap.pop(); } cout << res << '\n'; return; }
D - 2-variable Function
題目描述:對於方程\(x = a^3 +a^2b +ab^2 + b^3\),給定一個整數\(n\),求大於等於\(n\)的最小正整數\(x\),使得存在非負整數對\((a , b)\),使得上述等式成立。
思路:顯然我們可以列舉\(a\),其範圍為\(0 \leq a \leq 1e6\),此時\(a\)可以當做常數看待,原等式可以改寫成以下不等式:
\[b^3 + ab^2 + a^2b \geq x - a^3 \]不等式左邊是非負的,所以在正整數範圍內以\(b\)為引數的函式是單調遞增的,所以可以二分去查詢一個最小的\(b\)使得該不等式成立。
時間複雜度:\(O(10^6log10^6)\)
參考程式碼:
void solve() {
long long x;
cin >> x;
long long res = LLONG_MAX;
for (int i = 0; i <= 1e6; ++i) {
long long a = i;
long long y = x - a * a * a;
int lr = 0, rs = 1e6, ans = 0;
while (lr <= rs) {
long long mid = lr + rs >> 1;
long long cur = mid * mid * mid + a * mid * mid + a * a * mid;
if (cur >= y) ans = mid, rs = mid - 1;
else lr = mid + 1;
}
long long cur = a * a * a + 1ll * ans * ans * ans + a * a * ans + a * ans * ans;
res = min(res, cur);
}
cout << res << '\n';
return;
}
E - Bishop 2
題目描述:你初始時在\((sx , sy)\)位置,你需要到\((ex , ey)\)位置,網格上有障礙物,你只能走斜對角線,每次行走,只要沒有障礙物,你可以走任意遠。問從起點到終點的最小次數。
思路:比較明顯的BFS
,但因為一步可以走任意遠,所以噹噹前列舉的點的步數大於列舉的下一個點的步數時提前跳出,進行優化。
時間複雜度:\(O(能過)\)
參考程式碼:
void solve() {
int n;
int sx, sy, ex, ey;
cin >> n >> sx >> sy >> ex >> ey;
vector<string>strs(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> strs[i];
strs[i] = ' ' + strs[i];
}
vector<vector<int>>dis(n + 1, vector<int>(n + 1, 0x3f3f3f3f));
dis[sx][sy] = 0;
using PII = pair<int, int>;
queue<PII> q;
q.push({ sx , sy });
while (!q.empty()) {
auto [x, y] = q.front();
q.pop();
int dist = dis[x][y] + 1;
for (int d = 1; d <= n; ++d) {
int nx = x - d, ny = y - d;
if (nx < 1 || ny < 1 || strs[nx][ny] == '#') break;
if (dis[nx][ny] < dist) break;
dis[nx][ny] = dist;
q.push({ nx , ny });
}
for (int d = 1; d <= n; ++d) {
int nx = x + d, ny = y + d;
if (nx > n || ny > n || strs[nx][ny] == '#') break;
if (dis[nx][ny] < dist) break;
dis[nx][ny] = dist;
q.push({ nx , ny });
}
for (int d = 1; d <= n; ++d) {
int nx = x + d, ny = y - d;
if (nx > n || ny < 1 || strs[nx][ny] == '#') break;
if (dis[nx][ny] < dist) break;
dis[nx][ny] = dist;
q.push({ nx , ny });
}
for (int d = 1; d <= n; ++d) {
int nx = x - d, ny = y + d;
if (nx < 1 || ny > n || strs[nx][ny] == '#') break;
if (dis[nx][ny] < dist) break;
dis[nx][ny] = dist;
q.push({ nx , ny });
}
}
if (dis[ex][ey] == 0x3f3f3f3f) dis[ex][ey] = -1;
cout << dis[ex][ey] << '\n';
return;
}
F - typewriter
題目描述:給你\(n\)個鍵盤, 每個鍵盤可以列印的字元由一個字串給出,現在列印長度為\(L\)的字串,每次可以選擇一個鍵盤列印, 問共可以打印出多少不同的字串。
思路:考慮容斥,以\(n = 3\)為例,最終答案為:只使用第一個鍵盤 + 只使用第二個鍵盤 + 只使用第三個鍵盤 - 使用第一個和第二個鍵盤 - 使用第一個和第三個鍵盤 - 使用第二個和第三個鍵盤 + 使用所有鍵盤。考慮到\(n\)很小,可以暴力列舉使用的鍵盤的數量,然後根據使用數量的奇偶來判斷是加還是減,每種情況對答案的貢獻為使用的鍵盤的字符集的交集的模的\(L\)次冪,即假設使用的\(k\)個鍵盤都含有的字元的種數為\(m\),則對答案的貢獻是\(m^L\)。
時間複雜度:\(O(2^n logL)\)
參考程式碼:
const int mod = 998244353;
void solve() {
int n, L;
cin >> n >> L;
vector<int>typewriter;
string s;
for (int i = 0; i < n; ++i) {
cin >> s;
int x = 0;
for (auto&& c : s) x |= (1 << (c - 'a'));
typewriter.push_back(x);
}
auto quickPow = [&](int a, int p)->int {
int ans = 1;
while (p) {
if (p & 1) ans = 1ll * ans * a % mod;
p >>= 1;
a = 1ll * a * a % mod;
}
return ans;
};
auto cal = [](int x)->int {
int cnt = 0;
for (int i = 30; i >= 0; --i) cnt += (x >> i) & 1;
return cnt;
};
int res = 0;
for (int i = 1; i < 1 << n; ++i) {
int ch = (1 << 26) - 1;
for (int j = 0; j < n; ++j) {
if (i & (1 << j)) ch &= typewriter[j];
}
int dx = cal(ch), dy = cal(i);
if (dy & 1) res = (res + quickPow(dx, L)) % mod;
else res = ((res - quickPow(dx, L)) % mod + mod ) % mod;
}
cout << res << '\n';
return;
}