AGC013 部分题目题解
C - Ants on a Circle
把掉头视作穿过,然后容易得到最后每只蚂蚁的位置。只需要确定哪只蚂蚁是 \(1\) 号蚂蚁。
统计有多少只蚂蚁穿过了 \(x=M−0.5\) 这个位置即可。
D - Pilling Up
相当于取出来一个又放进去一个,不妨把这个过程刻画到平面图上,去掉首尾,那么就是统计只能向三个方向走,起点为 \((0, 0), (1, 0), \dots, (N - 1, 0)\),不能越过 \(y = 0\) 与 \(y = N - 1\),形状不同的路径数量。
一个避免数重的简单方法是,枚举第一个碰到下边界的点,然后把两边的方案乘起来。
E - Placing Squares
嗯拆组合意义:
- 有黑球、红球、蓝球三种球;
- 每个位置上最多放一个黑球,有的位置不能放黑球。
- 记两个相邻的黑球的位置分别为 \(x, y\)(\(x < y\)),那么 \([x, y)\) 之间有恰好一个红球和一个蓝球。
记录所有可能的状态,使用矩阵快速幂优化转移即可。
F - Two Faced Cards
固定 \(Z\),用 Hall 定理刻画,把 \(Y\) 中的牌视为左部点,那么只需对排序后 \(Y\) 中的前缀检查。
每个 \(C_i\) 相当于给某个 \(S_i\) 的 \([C_i, +\infty)\) 位置上都减了 \(1\),而如果钦定每个 \(Z\) 中的卡牌先选正面上的元素,并枚举选 \(D_i, E_i\),那么就继续转化为以下问题:
- 给定若干区间 \([l_i, r_i]\)(每次询问都固定),每次可选择一些区间,把这些区间内的 \(S_i\) 加 \(1\)(多个区间算多次),给定 \(k\),求使得 \(\forall i \le k\),\(S_i \ge 0\),且 \(\forall i > k\),\(S_i \ge -1\),最少操作多少个区间。
至此我们终于可以发现,可以运用贪心,从右往左扫描,找到第一个不合法位置 \(i\),并选择 \(l_P\) 最小且覆盖 \(i\) 的区间 \(P\)。观察问题形式,我们完全可以先令 \(k = 0\) 跑一次,再从小到大扫描 \(k\),使用堆可以简单维护。
你可能会疑惑为什么一定要从大到小跑,下面给出一个证明:
证明:对于某个 \(k\) 和一个合法解,我们找到区间 \(Q\),表示右端点最小的,且覆盖 \(i\) 的区间,进行分类讨论:
- \(k > i\),则我们发现 \(Q\) 的右端点肯定会被另一个覆盖 \(i\) 的区间 \(R\) 覆盖,那么对 \(i \le j \le r_Q\),\(S_j\) 肯定大于 \(0\),直接将 \(Q\) 改为 \(P\) 不劣;
- 否则,我们既然已经合法,就直接把 \(Q\) 改成 \(P\) 不劣。
其实整个过程就是,不断简化问题,转化为更简单的形式,转化完了就做完了,以后还是要多想啊!
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline ll Read() {
ll x = 0; int sig = 1; char c = getchar();
while(!isdigit(c)) { if(c == '-') sig = -1; c = getchar(); }
while(isdigit(c)) x = (x << 3) + (x << 1) + (c ^ '0'), c = getchar();
return x * sig;
}
void Write(ll x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) Write(x / 10);
putchar((x % 10) ^ 48);
}
const int N = 100005;
int n, m, _m, k, a[N], b[N], c[N], d[N], uc[N], s[N], ans[N];
pair<int, int> p[N], _p[N];
bool del[N];
void Quit() { int T = Read(); while(T--) printf("-1\n"); exit(0); }
int main() {
int i; n = Read() + 1;
for(i = 1; i < n; i++) a[i] = Read(), b[i] = Read();
for(i = 1; i <= n; i++) uc[i] = c[i] = Read();
sort(uc + 1, uc + n + 1), k = unique(uc + 1, uc + n + 1) - uc - 1;
for(i = 1; i <= n; i++) s[lower_bound(uc + 1, uc + k + 1, c[i]) - uc]--;
for(i = 1; i < n; i++) {
a[i] = lower_bound(uc + 1, uc + k + 1, a[i]) - uc;
b[i] = lower_bound(uc + 1, uc + k + 1, b[i]) - uc;
s[a[i]]++;
if(b[i] < a[i]) m++, p[m] = make_pair(a[i] - 1, b[i]);
}
for(i = 1; i <= k; i++) s[i] += s[i - 1];
if(m) sort(p + 1, p + m + 1), reverse(p + 1, p + m + 1);
int cur = 0, j = 1, rem = n - 1;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
for(i = k; i; i--) {
cur += d[i];
while(j <= m && p[j].first >= i) q.emplace(p[j].second, j), j++;
while(s[i] + cur < -1) {
if(q.empty() || q.top().first > i) Quit();
d[q.top().first - 1]--, d[p[q.top().second].first]++;
del[q.top().second] = true, q.pop(), rem--, cur++;
}
}
for(i = k; i; i--) d[i] += d[i + 1], s[i] += d[i];
ans[0] = rem, cur = 0, memset(d, 0, sizeof(d));
for(i = 1; i <= m; i++) if(!del[i]) _p[++_m] = make_pair(p[i].second, p[i].first);
if(_m) sort(_p + 1, _p + _m + 1);
while(!q.empty()) q.pop();
for(i = j = 1; i <= k; i++) {
cur += d[i];
while(j <= _m && _p[j].first <= i) q.emplace(-_p[j].second, j), j++;
while(s[i] + cur < 0) {
if(q.empty() || -q.top().first < i) break;
d[-q.top().first + 1]--, d[_p[q.top().second].first]++;
q.pop(), rem--, cur++;
}
if(s[i] + cur < 0) {
while(i <= k) ans[i++] = -N * 2;
break;
}
ans[i] = rem;
}
int T = Read();
while(T--) {
int x = Read(), y = Read();
x = lower_bound(uc + 1, uc + k + 1, x) - uc - 1;
y = lower_bound(uc + 1, uc + k + 1, y) - uc - 1;
Write(max(-1, max(ans[x] + 1, ans[y]))), putchar('\n');
}
}

浙公网安备 33010602011771号