比赛链接: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) 换到应该的位置上,那么 (0) 也就是确定了。
(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;
}