A. A Hero Named Magnus
#include <bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int, int>;
using vi = vector<int>;
void solve(){
int x;
cin >> x;
cout << 2ll * x - 1 << "\n";
return ;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
for( cin >> T ; T ; T -- )
solve();
return 0;
}
B. A Plus B Problem
对于两个数的加法,一位最多只能被进位一次。
并且进位方式的情况一定是当前位\(i\)向右连续若干位(可以是 0 位)都是\(9\),直到\(j\)第一个满足\(a_j+b_j\ne 9\)的情况下,判断\(a_j+b_j>=10\)即可知道当前位是否被进位。
而当前位进位向左可以进多少位呢?会进连续的\(a_j+b_j=9\)位,所以我们要早到第一个和不为 9 的位置。
所以我们要动态的维护所有和不等于 9 的位置,并且找到一个位置的前驱和后继,所以可以使用set
来维护信息。
#include <bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int, int>;
using vi = vector<int>;
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, q;
cin >> n >> q;
string sa, sb;
cin >> sa >> sb;
vi a(n + 1), b(n + 1);
set<int> s;
for (int i = 1; i <= n; i++) {
a[i] = sa[i - 1] - '0', b[i] = sb[i - 1] - '0';
if (a[i] + b[i] != 9) s.insert(i);
}
for (int r, id, d, res, val, tmp; q; q--) {
cin >> r >> id >> d;
res = 2; // 至少有两位不同,剩下是进位造成的不同
auto it = s.upper_bound(id);
if (it == s.end()) { // 计算修改前的值
val = a[id] + b[id];
} else {
int nxt = *(it);
val = a[id] + b[id] + ((a[nxt] + b[nxt]) >= 10);
}
// 修改值
if (r == 1) {
if (d == a[id]) { // 没有变化
cout << val % 10 << " 0\n";
continue;
}
if (d + b[id] != 9) s.insert(id);
else s.erase(id);
a[id] = d;
} else {
if (d == b[id]) { // 没有变化
cout << val % 10 << " 0\n";
continue;
}
if (d + a[id] != 9) s.insert(id);
else s.erase(id);
b[id] = d;
}
// 重新计算值
it = s.upper_bound(id);
if (it == s.end()) {
tmp = (a[id] + b[id]);
} else {
int nxt = (*it);
tmp = a[id] + b[id] + ((a[nxt] + b[nxt]) >= 10);
}
cout << tmp % 10 << " ";
if (tmp < 10 and val >= 10) { // 原本进位,现在不进位,要计算出原来进了多少位
auto its = s.lower_bound(id);
if (its != s.begin()) {
its = prev(its), res += (id - (*its));
} else res += id - 1;
}else if ( tmp >= 10 and val < 10 ) { // 现在进位,原来不进位 ,要计算出现在进了多少位
auto its = s.lower_bound(id);
if (its != s.begin()) {
its = prev(its), res += (id - (*its));
} else res += id - 1;
}
cout << res << "\n";
}
return 0;
}
D. Assumption is All You Need
首先交换操作一定会使得逆序对的数量减少,所以\(A\)的逆序程度一定大于\(B\)的逆序程度,否则无解。
我们从左向右逐位判断,如果当前位\(i\) 满足前\(i-1\)位都合法,如果\(a_i< b_i\)则一定无解。反之我们要在后面找\(a_j=b_i\)然后交换过来。但是请注意,对于样例 3 就可以看出如果交换一步到位会使得\(A\)的逆序程度迅速减小,从而导致后续点无法交换,所以我们要使得每一次交换减小的逆序对数量最少。也即只要遇到\(a_j\)满足\(b_i\le a_j < a_i\)就把\(a_i,a_j\)交换。
#include <bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int, int>;
using vi = vector<int>;
void solve() {
int n;
cin >> n;
vi a(n), b(n);
for (auto &i: a) cin >> i;
for (auto &i: b) cin >> i;
vector<pii> res;
for (int i = 0; i < n; i++) {
if (a[i] == b[i]) continue;
if (a[i] < b[i]) {
cout << "-1\n";
return;
}
for (int j = i + 1; j < n; j++)
if (a[j] < a[i] and a[j] >= b[i]) {
res.emplace_back(i + 1, j + 1);
swap(a[i], a[j]);
if (a[i] == b[i]) break;
}
}
cout << res.size() << "\n";
for (auto [x, y]: res)
cout << x << " " << y << "\n";
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
for (cin >> T; T; T--)
solve();
return 0;
}
E. Buy and Delete
可以注意到是,Bob对于任意有向环,最多只需要两次就可以把所有的边全部删掉。
所以对于Alice来说,只要考考虑能不能买的起最小环,如果可以答案为 2。
如果不行,考虑能不能买得起最短边,如果可以,则答案为 1,反之为 0。
为什么两次一定可以把环全部删掉,很简单,对于有向边\((u,v)\),第一次删除所有\(u<v\)的边,在删除所有\(u>v\)的边,即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using pii = pair<int, int>;
using db = long double;
constexpr int inf = 1E18;
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, c;
cin >> n >> m >> c;
vector<array<int, 3>> e(m);
vector<vector<pii>> g(n + 1);
int minEdge = inf, minCycle = inf;
for (auto &[x, y, w]: e)
cin >> x >> y >> w, g[x].emplace_back(y, w), minEdge = min(minEdge, w);
vi dis;
auto dij = [&dis, n, g](array<int, 3> ban) {
dis = vi(n + 1, inf);
dis[ban[1]] = 0;
vi vis(n + 1, 0);
priority_queue<pii, vector<pii>, greater<pii> > q;
q.emplace(0, ban[1]);
for (int u; !q.empty();) {
u = q.top().second, q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (const auto &[v, w]: g[u]) {
if (u == ban[0] and v == ban[1] and w == ban[2]) continue;
if (dis[v] <= dis[u] + w) continue;
dis[v] = dis[u] + w, q.emplace(dis[v], v);
}
}
};
for (auto edge: e) {
dij(edge);
minCycle = min(minCycle, edge[2] + dis[edge[0]]);
}
if (minCycle <= c)
cout << "2\n";
else if (minEdge <= c)
cout << "1\n";
else
cout << "0\n";
return 0;
}
G. Occupy the Cities
考虑二分答案,设二分的枚举值为\(x\),对于\(i\)位置上的\(1\),一定可以覆盖到\([i-x+1,i+x-1]\),而对于\(i-x,i+x\)的覆盖只能二选一。
所以我们从左向后的遍历,维护上一个\(1\)覆盖到的位置,如果\(i-x\)被覆盖到了,则对于\(i\)来说覆盖\(i+x\)肯定更优,反之则覆盖\(i-x\),但请注意如果\(i-x-1\)没有被覆盖到,则说明两个 1 的不能覆盖之间所有的 0,则当前\(x\)太小了。
#include <bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int, int>;
using vi = vector<int>;
void solve() {
int n;
string s;
cin >> n >> s;
if( s == string( n , '1' )){
cout << "0\n";
return ;
}
auto check = [s, n](int x) {
int lst = 0;
for (int i = 0; i < n; i++) {
if (s[i] == '0') continue;
if (lst < i - x) return false;
else if (lst == i - x) lst = i + x;
else lst = i + x + 1;
}
return lst >= n;
};
int l = 0, r = n, res = -1;
for (int mid; l <= r;) {
mid = (l + r) / 2;
if (check(mid)) res = mid, r = mid - 1;
else l = mid + 1;
}
cout << res << "\n";
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
for (cin >> T; T; T--)
solve();
return 0;
}
I. PTSD
最优解肯定是两个一组的分配
倒序维护一个计数器统计没有配对的人。
#include <bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int, int>;
using vi = vector<int>;
void solve(){
int n , cnt = 0 , res = 0;
string s;
cin >> n >> s;
for( int i = n ; i >= 1 ; i -- ){
if( s[i-1] == '0' ) cnt ++;
else {
if( cnt > 0 ) res += i , cnt --;
else cnt ++;
}
}
cout << res << "\n";
return ;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
for( cin >> T ; T ; T -- )
solve();
return 0;
}
- Programming Collegiate Contest Guilin Chinaprogramming collegiate contest guilin guilin programming collegiate universal programming collegiate provincial contest programming collegiate jiangsu contest international programming collegiate contest programming collegiate mianyang contest programming collegiate shenzhen contest programming collegiate shanghai contest programming collegiate contest harbin programming collegiate codeforces contest