Codeforces Round #791 (Div. 2)(A-D)
A. AvtoBus
题意:
给你 n, 问满足 4 x + 6 y = n 4x+6y=n 4x+6y=n 的 x + y x+y x+y的最小值和最大值是多少? x , y x,y x,y 都是非负整数。
题解:
n如果是奇数,无解。如果是偶数,等式除以2,考虑 2 x + 3 y = n 2x+3y=n 2x+3y=n 。
要想使得 x + y x+y x+y尽可能大,那么x要尽量多,就需要找最小的y满足 n − 3 y n-3y n−3y是偶数,分别讨论摸3的各种情况。反之同理。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
ios::sync_with_stdio(false), cin.tie(0);
int t;
ll n;
cin >> t;
while (t--) {
cin >> n;
if (n & 1 || n == 2) {
cout << -1 << endl;
continue;
}
n /= 2;
ll mi = 1e9, mx = 0;
if (n < 4) {
cout << "1 1" << endl;
continue;
}
switch (n % 3) {
case 0:
mi = n / 3;
break;
case 1:
mi = (n - 4) / 3 + 2;
break;
case 2:
mi = (n - 2) / 3 + 1;
break;
default:
break;
}
if (n & 1) {
mx = max(mi, 1 + (n - 3) / 2);
}
else {
mx = max(mi, n / 2);
}
cout << mi << ' ' << mx << endl;
}
return 0;
}
B. Stone Age Problem
题意:
给你 长度为 n n n的数组 a a a, 有两种操作:
- 把 a i a_i ai改成 x x x
- 把所有数改成 x x x
输出每次操作后
题解:
单点更新,区间更新,维护区间和,这不就是线段树吗,练板子了。。。。当然,这里是区间赋值
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAXN = 2e5 + 10;
const int MOD = 1e9 + 7;
int n, q, a[MAXN];
struct node {
int l, r;
ll lazy;
ll sum;
} tr[MAXN << 2];
inline int lson(int x) {
return x << 1;
}
inline int rson(int x) {
return x << 1 | 1;
}
void pushup(int x) {
tr[x].sum = tr[lson(x)].sum + tr[rson(x)].sum;
}
void pushdown(int x) {
if (tr[x].lazy) {
tr[lson(x)].lazy = tr[x].lazy;
tr[rson(x)].lazy = tr[x].lazy;
tr[lson(x)].sum = (tr[lson(x)].r - tr[lson(x)].l + 1) * tr[x].lazy;
tr[rson(x)].sum = (tr[rson(x)].r - tr[rson(x)].l + 1) * tr[x].lazy;
tr[x].lazy = 0;
}
}
void build(int x, int l, int r) {
tr[x].l = l, tr[x].r = r, tr[x].lazy = 0;
if (l == r) {
return;
}
int mid = l + r >> 1;
build(lson(x), l, mid);
build(rson(x), mid + 1, r);
pushup(x);
}
ll query(int x, int l, int r) {
if (tr[x].l >= l && tr[x].r <= r)
return tr[x].sum;
if (tr[x].l > r || tr[x].r < l)
return 0;
pushdown(x);
return query(lson(x), l, r) + query(rson(x), l, r);
}
void update(int x, int l, int r, ll k) {
if (tr[x].l >= l && tr[x].r <= r) {
tr[x].lazy = k;
tr[x].sum = (tr[x].r - tr[x].l + 1) * k;
return;
}
if (tr[x].l > r || tr[x].r < l)
return;
pushdown(x);
update(lson(x), l, r, k);
update(rson(x), l, r, k);
pushup(x);
}
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> q;
build(1, 1, n);
for (int i = 1; i <= n; i++) {
int a;
cin >> a;
update(1, i, i, a);
}
while (q--) {
int t, x, i;
cin >> t;
if (t == 1) {
cin >> i >> x;
update(1, i, i, x);
}
else {
cin >> x;
update(1, 1, n, x);
}
cout << query(1, 1, n) << endl;
}
return 0;
}
C. Rooks Defenders
题意:
给你 n*n的国际象棋棋盘,有3种操作:
- 在 ( i , j ) (i,j) (i,j)处放一个车
- 移除 ( i , j ) (i,j) (i,j)处的车
- 查询矩形 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1), (x_2,y_2) (x1,y1),(x2,y2)的所有点是不是都被车攻击到
题解:
用两个树状数组维护行和列能不能被车吃到,放子的时候,注意幂等,也就是说,这一行/列如果已经被车吃到了,就不用放了。
也可以用线段树做,维护区间最小值。
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> pii;
const int MAXN = 2e5 + 10;
const int MOD = 1e9 + 7;
int n, q;
int tr1[MAXN], tr2[MAXN];
int r[MAXN], c[MAXN];
inline int lowbit(int x) {
return x & (-x);
}
void add(int* tr, int i, int d) {
while (i <= n) {
tr[i] += d;
i += lowbit(i);
}
}
int sum(int* tr, int i) {
int res = 0;
while (i > 0) {
res += tr[i];
i -= lowbit(i);
}
return res;
}
signed main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
ios::sync_with_stdio(false), cin.tie(0);
int t;
int x, y, x1, x2, y1, y2;
cin >> n >> q;
while (q--) {
cin >> t;
if (t == 1) {
cin >> x >> y;
r[x]++, c[y]++;
if (r[x] == 1) add(tr1, x, 1);
if (c[y] == 1) add(tr2, y, 1);
}
else if (t == 2) {
cin >> x >> y;
r[x]--, c[y]--;
if (r[x] == 0) add(tr1, x, -1);
if (c[y] == 0) add(tr2, y, -1);
}
else {
cin >> x1 >> y1 >> x2 >> y2;
bool row = sum(tr1, x2) - sum(tr1, x1 - 1) >= x2 - x1 + 1;
bool col = sum(tr2, y2) - sum(tr2, y1 - 1) >= y2 - y1 + 1;
puts((row || col) ? "Yes" : "No");
}
}
return 0;
}
D.Toss a Coin to Your Graph…
题意:
给你一个图,选择一条长度为 k − 1 k-1 k−1的路径,使得沿路k个点的点权的最大值最小
题解:
看到最X值最X,刻在DNA里就是“二分答案“,那么我们可以看出答案最大值为点权最大值1e9,最小值为0,二分答案记为mid,则问题转化为:
是否存在一条长度为 k − 1 k-1 k−1 的路径,使得沿路k个点的点权不超过 m i d mid mid ?
可以想到,如果存在,那么这条路径经过的点的点权都不超过mid,那就一定在原图里面点权小于mid的子图里面,则问题可以进一步转化为:
给你一个图,是否存在长度为 k − 1 k-1 k−1的路径?
这样问题就变得容易解决了,首先如果有环,一定存在任意长度的路径。文章来源:https://www.toymoban.com/news/detail-451467.html
否则是个dag图,拓扑排序的时候记录dp[i]表示从入度为0的点走到i点的最长路径,如果走到了k,则直接返回true,否则拓扑排序出来之后判断是否仍有入度不为0的点,如果有,说明一定存在环,若存在环,就说明任意长度的路径都存在,返回true,否则为false。文章来源地址https://www.toymoban.com/news/detail-451467.html
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAXN = 2e5 + 10;
const int MOD = 1e9 + 7;
int n, m;
ll k;
ll a[MAXN];
vector<int> g[MAXN];
int in[MAXN];
bool vis[MAXN];
int dp[MAXN];
// 建一个新图
vector<int> g2[MAXN];
unordered_set<int> s;
// if exists path which max number of it <= x
bool check(int x) {
s.clear();
for (int i = 1; i <= n; i++) {
in[i] = vis[i] = dp[i] = 0;
g2[i].clear();
if (a[i] <= x) s.insert(i), dp[i] = 1;
}
for (int i = 1; i <= n; i++) {
for (auto j : g[i]) {
if (s.find(i) != s.end() && s.find(j) != s.end()) {
g2[i].push_back(j);
in[j]++;
}
}
}
queue<int> q;
for (int i = 1; i <= n; i++) {
if (s.find(i) != s.end() && !in[i]) q.push(i);
}
while (!q.empty()) {
int j = q.front();
q.pop();
vis[j] = true;
if (dp[j] >= k) return true;
for (auto u : g2[j]) {
if (!vis[u]) {
dp[u] = max(dp[u], dp[j] + 1);
if (dp[u] >= k) return true;
in[u]--;
if (!in[u]) q.push(u);
}
}
}
for (int i = 1; i <= n; i++) {
if (s.find(i) != s.end() && in[i]) return true;
}
return false;
}
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
}
ll l = 0, r = 1e9;
while (l < r) {
ll mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
// cout << l << endl;
if (check(l))cout << l << endl;
else cout << -1 << endl;
return 0;
}
到了这里,关于Codeforces Round #791 (Div. 2)(A-D)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!