AtCoder Regular Contest 119 (ABC題)
比賽連結:Here
A - 119 × 2^23 + 1
注意到 \(2^{60} > 10^{18}\) ,所以我們可以直接列舉 \(0\) ~ \(59\)
int main() { cin.tie(nullptr)->sync_with_stdio(false); ll n; cin >> n; ll ans = (1ll << 60); for (int i = 0; i < 60; ++i) { ll a = n / (1ll << i); ll b = i; ll c = n - a * (1ll << i); ans = min(ans, a + b + c); } cout << ans; }
B - Electric Board
給定長度為 \(n\) 兩個字串 \(S,T\),要求通過最少的運算元把 \(S\) 變成 \(T\),操作就是對於 \(s_l=0∧s_{l+1}=...=s_r=1\) 或者 \(s_l=1∧s_{l+1}=...=s_r=0\) 可以交換元素 \(s_l\) 和 \(s_r\)
\(2≤n≤500000\)
解法1
我們可以把所有 \(0\) 換到應該的位置上,那麼 \(1\) 也就確定了。
\(0\) 換過去的代價是路上 \(0\) 的數量,這就和 \(1\) 沒關係了,那麼我們把 \(S,T\) 的 \(0\) 都取出來,相鄰的配對即可。
解法2
我們可以把所以 \(1\)
\(1\) 換過去的代價是路上 \(0\) 的數量,這和 \(0/1\) 都有關係,直接匹配是行不通的,正確的做法是從左往右掃,如果遇到 \(S\) 有 \(1\) 但是 \(T\) 沒有就把他移動到右邊第一個 \(0\),如果 \(T\) 有 \(1\) 但是 \(S\) 沒有也把他移動到右邊第一個 \(0\)
這種做法的正確性有二:一是兩個狀態都往中間靠攏;二是我們永遠在不得不操作的時候操作。
int main() { cin.tie(nullptr)->sync_with_stdio(false); int n; string s, t; cin >> n >> s >> t; vector<int>a, b; for (int i = 0; i < n; ++i) { if (s[i] == '0') a.push_back(i); if (t[i] == '0') b.push_back(i); } if (int(a.size() != int(b.size()))) {cout << -1; return 0;} int ans = 0; for (int i = 0; i < int(a.size()); ++i) if (a[i] != b[i]) ans++; cout << ans; }
C - ARC Wrecker 2
有 \(n\) 個樓房,第 \(i\) 個高為 \(a_i\),相鄰的樓房可以同時增加或同時減少,問能夠推平(高度全部變成 \(0\))的區間有多少個。
\(2≤n≤300000,1≤ai≤10^9\)
解法
一定要有敏銳的觀察能力,這道題的結論是:如果奇偶位置高度相同則可以推平。
證明不難,因為無論怎麼操作奇偶的差都是不變的,而目標奇偶差值為 \(0\),初始狀態一定能到目標狀態。
然後搞一個特殊的字首和,奇數位置符號為正,偶數位置符號為負,找權值和為 \(0\) 的區間即可。
const int N = 3e5 + 10;
ll n, ans, a[N];
map<ll, ll>mp;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
if (i > 1) a[i] += a[i - 2];
}
mp[0] = mp[a[1]] = 1;
for (int i = 1; i <= n / 2; ++i) {
int x = 2 * i;
ans += mp[a[x - 1] - a[x]];
if (x < n) ans += mp[a[x + 1] - a[x]];
mp[a[x - 1] - a[x]]++;
mp[a[x + 1] - a[x]]++;
}
cout << ans;
}
ll a[1 << 19], b[1 << 19], c[1 << 19];
map<ll, ll>d;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
ll n, ans = 0;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i) {
if (i & 1) b[i] = a[i];
else b[i] = -a[i];
c[i] = c[i - 1] + b[i];
}
for (int i = 0; i <= n; ++i) {
ans += d[c[i]];
d[c[i]] += 1;
}
cout << ans;
}
The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。