初衷
看到题解区的其他题解都没怎么证明自己的做法,故补上一篇以证明为主的题解。同时我认为这是一道很好的练习做法基础证明的题。
思路
简单模拟样例,我们可以发现,答案是这样出现的:
- 初始每头牛的身高都是 \(h\)。
- 每遇到一条信息 \([l,r]\),其中 \(l\) 表示两个数的较小值,\(r\) 表示两个数的较大值,都把 \((l,r)\) 区间内的牛的身高减去 \(1\)。
现在问题来了:凭什么认为这个做法是正确的呢?
证明
注意:下文所指的区间全部是开区间 \((l,r)\),即对奶牛进行操作的区间。
首先,看到题面上一句很重要的话:
在所有给定信息都成立的前提下
什么意思?就是信息之间不可能存在矛盾。
什么时候会存在矛盾?当两个区间部分重叠的时候。
看这个例子:

由第一条要求 \([a_1,b_1]\) 得 \(b_2 < a_1\)。
由第二条要求 \([a_2,b_2]\) 得 \(a_1 < b_2\),矛盾。
由此得证,两个区间之间一定不可能部分重叠。
现在两个区间之间的关系只剩下分离和包含两种情况了。
对于第 \(i\) 头牛,身高为 \(h_i\),如果有两个包含该点的区间,它们必然有公共点,根据上面的结论它们只能是包含关系,因此这些区间按大小可以排成一个链。就像这样:

于是有如下的不等式,其中 \(k\) 表示包含第 \(i\) 头牛的区间数量:
由于题目求的是最大身高,所以每条不等式都要尽可能取紧,才能让所有牛的身高最大化。
最优方案是取 \(h_{a_2} = h_{a_1}-1\),\(h_{a_3} = h_{a_1}-2\),以此类推。最后 \(h_i\) 就等于 \(h_{a_1} - k\)。
由于所有的与区间 1 分离的区间都没有出现在图上,所以 \(h_{a_1}\) 就是最大身高。则 \(h_i\) 就等于最大身高减去包含第 \(i\) 头牛的区间数量。
那么当我遇到一个要求区间 \([l,r]\),将 \((l,r)\) 内的奶牛身高全部减一,则每头牛被减的次数就等于包含这头牛的区间数量。
由此得证,做法正确。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define div() cout << "-----------------------\n";
#define debug(n) cout << #n << " = " << n << "\n";
#define deb(n) cout << #n << " = " << n << " ";
int n,id,h,r;
int c[10005];
map<pair<int,int>,bool>vis;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> n >> id >> h >> r;
for(int i = 1;i <= n;i++){c[i] = h;}
for(int i = 1;i <= r;i++){
int a,b;cin >> a >> b;
if(vis[{a,b}]){continue;}
vis[{a,b}] = 1;
for(int j = min(a,b)+1;j < max(a,b);j++){
c[j]--;
}
}
for(int i = 1;i <= n;i++){
cout << c[i] << "\n";
}
return 0;
}
浙公网安备 33010602011771号