初衷

看到题解区的其他题解都没怎么证明自己的做法,故补上一篇以证明为主的题解。同时我认为这是一道很好的练习做法基础证明的题。

思路

简单模拟样例,我们可以发现,答案是这样出现的:

  1. 初始每头牛的身高都是 \(h\)
  2. 每遇到一条信息 \([l,r]\),其中 \(l\) 表示两个数的较小值\(r\) 表示两个数的较大值,都把 \((l,r)\) 区间内的牛的身高减去 \(1\)

现在问题来了:凭什么认为这个做法是正确的呢?

证明

注意:下文所指的区间全部是开区间 \((l,r)\),即对奶牛进行操作的区间。

首先,看到题面上一句很重要的话:

在所有给定信息都成立的前提下

什么意思?就是信息之间不可能存在矛盾。

什么时候会存在矛盾?当两个区间部分重叠的时候。

看这个例子:

abc

由第一条要求 \([a_1,b_1]\)\(b_2 < a_1\)

由第二条要求 \([a_2,b_2]\)\(a_1 < b_2\),矛盾。

由此得证,两个区间之间一定不可能部分重叠。

现在两个区间之间的关系只剩下分离和包含两种情况了。

对于第 \(i\) 头牛,身高为 \(h_i\),如果有两个包含该点的区间,它们必然有公共点,根据上面的结论它们只能是包含关系,因此这些区间按大小可以排成一个链。就像这样:

abc

于是有如下的不等式,其中 \(k\) 表示包含第 \(i\) 头牛的区间数量:

\[h_{a_1} > h_{a_2} > h_{a_3} > \dots > h_{a_k} > h_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;
}