AtCoder Beginner Contest 341 A-G
A
void solve()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cout << "10";
cout << "1" << endl;
}
B
void solve()
{
int n;
cin >> n;
vector<ll> a(n + 1, 0), t(n + 1, 0), s(n + 1, 0);
for (int i = 1; i <= n; i++)
cin >> a[i];
ll ans = 0;
for (int i = 1; i < n; i++)
{
cin >> s[i] >> t[i];
ll add = a[i] / s[i];
a[i + 1] += add * t[i];
}
cout << a[n] << endl;
}
C
暴力检查每个点
void solve()
{
int n, m, k, ans = 0;
cin >> n >> m >> k;
vector<vector<char>> a(n + 1, vector<char>(m + 1));
string s;
cin >> s;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
auto chk = [&](int x, int y) -> bool
{
for (auto i : s)
{
if (i == 'L')
y--;
else if (i == 'R')
y++;
else if (i == 'U')
x--;
else
x++;
if (x < 1 || x > n || y < 1 || y > m || a[x][y] == '#')
return false;
}
return true;
};
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (a[i][j] == '.')
ans += chk(i, j);
cout << ans << endl;
}
D
二分答案,check时容斥一下即可
void solve()
{
ll n, m, k;
cin >> n >> m >> k;
ll l = 1, r = 2e18, g = n / __gcd(n, m) * m;
auto check = [&](ll x) -> bool
{
ll num = x / n + x / m - 2 * (x / g);
return num >= k;
};
while (l < r)
{
ll mid = l + r >> 1;
if (check(mid))
r = mid;
else
l = mid + 1;
}
cout << l << endl;
}
E
发现每次反转对答案的影响只有\(l-,l\)和\(r,r+1\),用树状数组维护答案,线段树维护原数组
struct node
{
ll t, val, sz;
};
struct segtree
{
int n;
vector<node> a;
segtree(int _n) : n(_n * 4 + 10), a(n + 1) {}
void update(int id) { a[id].val = (a[id * 2].val + a[id * 2 + 1].val) % 2; }
void settag(int id, ll t)
{
a[id].val = (a[id].val + t * (a[id].sz)) % 2;
a[id].t = (a[id].t + t) % 2;
}
void pushdown(int id)
{
if (a[id].t)
{
settag(id * 2, a[id].t);
settag(id * 2 + 1, a[id].t);
a[id].t = 0;
}
}
void build(int id, int l, int r, vector<int> &arr)
{
a[id].t = 0;
a[id].sz = r - l + 1;
if (l == r)
a[id].val = arr[l];
else
{
int mid = l + r >> 1;
build(id * 2, l, mid, arr);
build(id * 2 + 1, mid + 1, r, arr);
update(id);
}
}
void modify(int id, int l, int r, int ql, int qr, ll t)
{
if (l == ql && r == qr)
{
settag(id, t);
return;
}
int mid = l + r >> 1;
pushdown(id);
if (qr <= mid)
modify(id * 2, l, mid, ql, qr, t);
else if (ql > mid)
modify(id * 2 + 1, mid + 1, r, ql, qr, t);
else
{
modify(id * 2, l, mid, ql, mid, t);
modify(id * 2 + 1, mid + 1, r, mid + 1, qr, t);
}
update(id);
}
ll query(int id, int l, int r, int ql, int qr)
{
if (l == ql && r == qr)
return a[id].val;
int mid = l + r >> 1;
pushdown(id);
if (qr <= mid)
return query(id * 2, l, mid, ql, qr);
else if (ql > mid)
return query(id * 2 + 1, mid + 1, r, ql, qr);
else
{
return (query(id * 2, l, mid, ql, mid) + query(id * 2 + 1, mid + 1, r, mid + 1, qr)) % 2;
}
}
};
struct BIT
{
int n;
vector<ll> a;
BIT(int _n) : n(_n), a(n + 1) {}
int lb(int x) { return x & -x; }
void build(int n, vector<int> &s)
{
for (int i = 1; i <= n; i++)
{
a[i] += s[i];
int fa = i + lb(i);
if (fa <= n)
a[fa] += a[i];
}
}
void add(int x, ll y)
{
for (; x <= n; x += lb(x))
a[x] += y;
}
ll query(int x)
{
ll res = 0;
for (; x; x ^= lb(x))
res += a[x];
return res;
}
int search(ll s) // 第一个小于等于s的位置
{
int pos = 0;
for (int j = 20; j >= 0; j--)
if (pos + (1 << j) <= n && a[pos + (1 << j)] <= s)
{
pos += (1 << j);
s -= a[pos];
}
return pos;
}
};
void solve()
{
int n, q;
string s;
cin >> n >> q >> s;
s = '#' + s;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
a[i] = s[i] - '0';
BIT bit(n);
segtree seg(n);
seg.build(1, 1, n, a);
for (int i = 2; i <= n; i++)
if (a[i] == a[i - 1])
bit.add(i - 1, 1), bit.add(i, 1);
int opt, l, r;
for (int i = 1; i <= q; i++)
{
cin >> opt >> l >> r;
if (opt == 1)
{
seg.modify(1, 1, n, l, r, 1);
if (l > 1)
{
int fi = seg.query(1, 1, n, l - 1, l - 1);
int se = seg.query(1, 1, n, l, l);
if (fi != se)
bit.add(l - 1, -1), bit.add(l, -1);
else
bit.add(l - 1, 1), bit.add(l, 1);
}
if (r < n)
{
int fi = seg.query(1, 1, n, r, r);
int se = seg.query(1, 1, n, r + 1, r + 1);
if (fi != se)
bit.add(r, -1), bit.add(r + 1, -1);
else
bit.add(r, 1), bit.add(r + 1, 1);
}
}
else
{
if (r - l > 1)
{
int chk = bit.query(r - 1) - bit.query(l);
cout << (chk ? "No" : "Yes") << endl;
}
else
{
if (l == r)
cout << "Yes" << endl;
else
{
cout << (seg.query(1, 1, n, l, l) != seg.query(1, 1, n, r, r) ? "Yes" : "No") << endl;
}
}
}
}
}
F
发现点只会从w大的到w小的,这样原图就变成了一个DAG,在这个图上对每个点跑一边01背包即可
void solve()
{
int n, m;
cin >> n >> m;
vector<vector<int>> e(n + 1);
vector<ll> a(n + 1), v(n + 1), d(n + 1, 0);
vector<ll> f(n + 1, 0), dp(N, 0);
vector<pii> edge(m);
for (auto &[u, v] : edge)
cin >> u >> v;
for (int i = 1; i <= n; i++)
cin >> v[i];
for (int i = 1; i <= n; i++)
cin >> a[i];
for (auto [x, y] : edge)
{
if (v[x] > v[y])
e[x].push_back(y), d[y]++;
if (v[x] < v[y])
e[y].push_back(x), d[x]++;
}
queue<int> q;
vector<int> ord;
for (int i = 1; i <= n; i++)
if (!d[i])
q.push(i);
while (q.size())
{
auto t = q.front();
ord.push_back(t);
q.pop();
for (auto to : e[t])
if (--d[to] == 0)
q.push(to);
}
reverse(ord.begin(), ord.end());
for (auto u : ord)
{
for (int i = 0; i <= v[u]; i++)
dp[i] = 0;
dp[0] = 1;
for (auto to : e[u])
for (int i = v[u] - 1; i >= v[to]; i--)
dp[i] = max(dp[i], dp[i - v[to]] + f[to]);
for (int i = 0; i < v[u]; i++)
f[u] = max(f[u], dp[i]);
}
ll ans = 0;
for (int i = 1; i <= n; i++)
ans += f[i] * a[i];
cout << ans << endl;
}
G
设s为a的前缀和,那么有:
$ ave=\frac{s[r]-s[k]}{r-k+1} $
发现这个式子的数学含义表示斜率,也就是说,要求出一个r,使得斜率最大
将数组反转,题目转化为:
$ ave=\frac{s[k]-s[r]}{k-r+1} $
用单调栈维护每个位置
只要当前i与q[r]的斜率小于等于i与q[r-1]的斜率,那么就可以删除r(上凸壳)
void solve()
{
int n;
cin >> n;
vector<ll> a(n + 1, 0), s(n + 1, 0);
for (int i = 1; i <= n; i++)
cin >> a[i];
reverse(a.begin() + 1, a.end());
for (int i = 1; i <= n; i++)
s[i] = s[i - 1] + a[i];
vector<int> q(n + 10, 0);
int r = -1;
q[++r] = 0;
vector<double> ans;
for (int i = 1; i <= n; i++)
{
while (r > 0 && (s[i] - s[q[r]]) * (q[r] - q[r - 1]) <= (s[q[r]] - s[q[r - 1]]) * (i - q[r]))
r--;
ans.push_back(1.0 * (s[i] - s[q[r]]) / (i - q[r]));
q[++r] = i;
}
reverse(ans.begin(), ans.end());
for (auto i : ans)
cout << i << endl;
}