Codeforces Round 885 (Div. 2)
A. Vika and Her Friends
枚举所有的点,判断是否存在点与Vika的距离和其他 k 个人的距离的奇偶性不同。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
void solve() {
int n, m, k, sx, sy;
cin >> n >> m >> k >> sx >> sy;
vector<int> x(k), y(k);
for (int i = 0; i < k; i++)
cin >> x[i] >> y[i];
for (int i = 1, p, f; i <= n; i++)
for (int j = 1; j <= m; j++) {
p = (abs(i - sx) + abs(j - sy)) % 2, f = 1;
for (int l = 0; f && l < k; l++) {
int q = (abs(i - x[l]) + abs(j - y[l])) % 2;
if (p == q) f = 0;
}
if (f) {
cout << "YES\n";
return;
}
}
cout << "NO\n";
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
B. Vika and the Bridge
预处理出所有的数出现的位置,然后枚举数,找到最大的间隔在间隔的最中间的位置插入一个,然后在统计出最大间隔即可。所有数字的最大间隔最小就是答案。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
void solve() {
int n, k;
cin >> n >> k;
vector<vector<int>> a(k + 1, vector<int>(1, 0));
for (int i = 1, x; i <= n; i++)
cin >> x, a[x].push_back(i);
for (int i = 1; i <= k; i++)
a[i].push_back(n + 1);
int res = INT_MAX;
for( const auto & v : a ){
multiset<int> s;
for( int i = 1 ; i < v.size() ; i ++ ){
s.insert( v[i] - v[i-1] - 1);
if( s.size() > 2 ) s.erase( s.lower_bound(*s.begin()) );
}
if( s.empty() ) continue;
int x = (*s.rbegin());
s.erase(s.lower_bound(x));
x -- , s.insert( x/2 ) , s.insert( (x+1) / 2 );
res = min( res , *s.rbegin());
}
cout << res << "\n";
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
C. Vika and Price Tags
我们只看一对数,当出现了某个数为0 的情况时,就会开始一个大小为 3 的循环。
所以我们要计算第一次\(a\)变为\(0\)需要消耗次数,模三后如果所有的答案都相同则输出YES
。
显然我们不可以去暴力的计算消耗次数,但是发现\(a>2b\)时,会出现\((a,b)->(b,a-b)->(a-b,a-2b)->(a-2b,b)\)刚好也是三次,所以可以直接对\(2b\)取模就可以快速变小。
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve() {
int n;
cin >> n;
vector<int> a(n), b(n);
for (auto &i: a) cin >> i;
for (auto &i: b) cin >> i;
for (int i = 0, t, c, last = -1; i < n; i++) {
if (a[i] == 0 && b[i] == 0) continue;
t = 0;
while (a[i] != 0) {
if (b[i] != 0 && a[i] > 2 * b[i]) a[i] %= 2 * b[i];
else c = abs(a[i] - b[i]), a[i] = b[i], b[i] = c, t = (t + 1) % 3;
}
if (last == -1) last = t;
else if (last != t) {
cout << "NO\n";
return;
};
}
cout << "YES\n";
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
D. Vika and Bonuses
很显然,可以想到一定是先执行s+=s%10
,再求和。
我们仅看个位数,发现
\[0\rightarrow 0\\
2 \rightarrow 4 \rightarrow 8 \rightarrow6\rightarrow2
\]
\(0\)没有变化,其他偶数在进行大小为\(4\)的循环,且一个循环可以增加\(20\)
再看其他情况
\[1\rightarrow2\\
3\rightarrow6\\
5\rightarrow0\\
7\rightarrow4\\
9\rightarrow8\\
\]
只要走一步,要么是\(0\),要么进入循环。
假设我们一开始先操作\(y=4x+i,i\in\{0,1,2,3\}\)
则总和为\(s’\times(k-y)\)。其中\(s’\)是操作\(x\)次后的结果,会发现大致符合单峰函数,似乎可以进行三分,但是样例就会发现不是完全符合三分的。
但是如果\(s’\)是操作\(i\)次后结果,则总和为\((s’+20x)-(k-4x-i)\)当\(i\)固定时,完全满足三分。所以可以枚举\(i\)然后三分\(x\)即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve() {
int s, k, res;
cin >> s >> k;
res = s * k;
s += s % 10, k--;
res = max(res, s * k);
if (s % 10 != 0) {
auto f = [s, k](int x) {
if (x > k) return 0ll;
int a = k - x, b = s;
b += (x / 4) * 20ll, x %= 4ll;
while (x--) b += b % 10;
return a * b;
};
for (int i = 0, l, r; i < 4; i++) {
l = 0, r = (k - i) / 4;
for (int lm, rm, fl, fr; r - l >= 10;) {
lm = l + (r - l + 1) / 3, rm = r - (r - l + 1) / 3;
fl = f(4 * lm + i), fr = f(4 * rm + i);
res = max({res, fl, fr});
if (fl == fr) l = lm + 1, r = rm - 1;
else if (fl < fr) l = lm + 1;
else r = rm - 1;
}
for (int j = l; j <= r; j++)
res = max(res, f(4 * j + i));
}
}
cout << res << "\n";
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}