题解 USACO24JAN-Ag Cowmpetency
USACO24 JAN Ag Competencey 题解
质量好高的思维题!但是赛时网络波动,最后一点时间才过了。
不难想到,我们先将所有的要求按照右端点排序。我们首先发现:
- 对于一个要求 \((a_i, h_i)\),所有 \([a_i, h_i)\) 之间的牛的领导力都低于 \(h_i\)。
从而,对于一个要求 \((a_i, h_i)\),所有 \([a_i, h_i)\) 之间的牛 \(a_j\),其之后第一头比 \(a_j\) 有严格更高领导力的牛都为 \(h_i\)。
根据上面的性质。假如有两个要求 \((a_i, h_i)\) 和 \((a_j, h_j)\) 两个要求,排序后 \(i < j\),如果后面的询问中 \(a_j\) 小于前一个询问的 \(h_i\),那么有解当且仅当 \(h_j = h_i\)。否则无解。
我们考虑画图来理解这个问题,之后每条线段代表一个要求,左边的圆点代表 \(a_i\),右边的三角代表 \(h_i\)
根据上面的性质,第一张图是一个合格的情况,而第二张图不是一个合格的情况。
我们更进一步思考,考虑两个 \(h_i\) 不同的要求之间的关系。
我们发现,对于所有 \(h\) 相同的询问,实际上只用保留一个最左端的 \(a\)。这是因为最左端的条件最强,即所有 \([a, h)\) 的牛的领导力都要比 \(h\) 和 \(a\) 弱,我们再来画个图,上个要求的 \(h\) 和下个要求 \(a\) 之间连一条实黑线:
\(max_1\) 是 \([h_{i - 1}, a_i]\) 中领导力最大的值,\(max_2\) 是 \((a_i, h_i)\) 中领导力最大的值。
对于 \([1, a_i]\),在 \(a_i\) 之后的第一个比 \([1, a_i]\) 大的牛是 \(h_i\),所以在 \((a_i, h_i)\) 之间的牛的领导力不能大于 \([1, a_i]\) 的,进而不能大于 \(max_1\),故 \(max_2\) 不能大于 \(max_1\)。
- 如果现有的 \(max_2 > max_2\),那么找 \([h_{i-1}, a_i]\) 中 最后一个 可以改的牛的领导力,将其改为 \(max_2\) (保证字典序最小)。如果找不到,那么无解。
- 如果 \(h_i\) 比前面的小,那么把 \(h_i\) 改为 \(\max(max_1, max_2) + 1\)。如果不可修改,那么无解。
现在我们也能更严谨的解释为什么只需要保证左端点最小的要求就可以了。如果已满足了它自己,那么对于比它左端点大的要求的 \(max_1\) 不变,\(max_2\) 只会变小。
在实现的时候,首先给所有为零的 \(c\) 填上 \(1\),这是保证不劣的。并标记这些 \(c\),方便后面修改。
注意在改完所有的之后判断每只牛的领导力是否小于 \(C\)。
由于每头牛只会被枚举一次,所以时间复杂度 \(O(n)\).
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int t, n, m, c, ci[MAXN], tag[MAXN];
struct qr{
int a, h;
bool operator < (const qr &x) const {
return a < x.a;
}
} q[MAXN];
void work()
{
scanf("%d%d%d", &n, &m, &c);
for(int i = 1; i <= n; i++) {
scanf("%d", &ci[i]);
tag[i] = ci[i];
if(!ci[i]) ci[i] = 1;
}
for(int i = 1; i <= m; i++) scanf("%d%d", &q[i].a, &q[i].h);
sort(q + 1, q + 1 + m);
q[0].h = 1;
for(int i = 1; i <= m; i++){
if(q[i].h == q[i - 1].h) continue;
if(q[i].h != q[i - 1].h && q[i].a < q[i - 1].h){
printf("-1\n");
return; // 判断是否无解
}
int mx1 = -1, mx2 = -1, cc = 0;
for(int j = q[i - 1].h; j <= q[i].a; j++){
mx1 = max(mx1, ci[j]);
if(tag[j] == 0) cc = j; // 找 max1
}
for(int j = q[i].a + 1; j < q[i].h; j++)
mx2 = max(mx2, ci[j]); // 找 max2
if(mx1 < mx2){
if(!cc) { printf("-1\n"); return;}
ci[cc] = mx2;
}
if(tag[q[i].h] && ci[q[i].h] <= max(mx1, mx2)){
printf("-1\n");
return; // 如果 h_i 不能被更改且不满足条件,那么无解
}
else if(tag[q[i].h] == 0)
ci[q[i].h] = max(mx1, mx2) + 1;
}
for(int i = 1; i <= n; i++)
if(ci[i] > c) {
printf("-1\n");
return;
}
printf("%d", ci[1]);
for(int i = 2; i <= n; i++){
printf(" %d", ci[i]);
}
printf("\n"); // 好坑,赛时竟然要判行末空格
return;
}
int main()
{
scanf("%d", &t);
while(t--) work();
return 0;
}