P1204 [USACO1.2]挤牛奶Milking Cows - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
差分在上学期和前缀和一起学了,不过一直没用到过,就忘了,倒是前缀和cf用的很多。
设 sum为前缀和数组,由前缀和
sum[i] = sum[i-1]+arr[i]
[l,r]的和为,sum[r] - sum[l-1]
示意:
而对前缀和公式移项:
sum[i] = sum[i-1]+arr[i] --> arr[i] = sum[i]-sum[i-1]
数学意义就是sn-sn-1=an
此时arr被称为差分数组
可以看出差分和前缀和其实是互逆得到操作。
------------------------------------------------
差分一般被用来标记区间。
如果要使[l,r]区间上每个元素a[i] 都加上C,
可以先得到a的差分数组b
因为a是b的前缀和,所以满足
a[i]=sum(b[1],b[2]....b[i])
如果使b[i]=b[i]+C
那么a数组中i之前的元素都没有变化,i之后的元素全部+C
这个很简单,如果使b[i]=b[i]+C,那么a[1],a[2]...a[i-1]都跟b[i]没关系,所以不改变
但是a[i],a[i+1],a[n] 因为都加上了b[i]所以值全部+C
而我们需要加C的区间为[l,r],所以令b[l]=b[l]+C,同时还需要让b[r+1]=b[r+1]-C。
看图就很好理解为什么b[r+1]需要-C了
b[l] + c,效果使得a数组中 a[l]及以后的数都加上了c(红色部分),但我们只要求l到r区间加上c, 因此还需要执行 b[r+1] - c,让a数组中a[r+1]及往后的区间再减去c(绿色部分),这样对于a[r] 以后区间的数相当于没有发生改变。
所以差分数组标记完区间后,对其求前缀和即可得到区间修改后的数组a。
回到本题
我们可以对有人工作的时间标记为1,无人工作的时间标记为0.最后统计整个区间内最长的连续1和最长的连续0.
而这个标记用的就是差分。
我们先初始化整个区间没人工作,全为0.然后在输入每个人工作时间的时候对工作时间的区间进行标记,有工作就+=1,没有就不加默认为0.
但是这题还有注意一点,设dif为差分数组。标记过程本来应该是
dif[l]+=1;
dif[r+1]-=1;
但是这题的工作时间为左开右闭的,所以写成
dif[l]++;
dif[r]--;
#include <bits/stdc++.h>
#include<iostream>
#include<thread>
using namespace std;
#pragma warning(disable:4996);
#define ll long long
#define int ll
#define endl "\n"
#define rep(j,b,e) for(int j=b;j<=e;j++)
int T;
const int N = 2e5 + 10;
int n, k, q;
void inline inln() {}
template<class T, class ...Arg>
void inline inln(T& t, Arg&...args) {
cin >> t;
inln(args...);
}
template<typename T>
void inline inln(vector<T>& arr, int n, int begin = 1) {
if (arr.size() >= n + 1) {
for (int j = begin; j <= n - 1 + begin; j++)
cin >> arr[j];
return;
}
int t;
if (begin == 1) {
arr.push_back(0);
}
for (int j = 1; j <= n; j++) {
cin >> t;
arr.push_back(t);
}
}
void inline pln() {
cout << "\n";
}
template <class T, class ...Arg>
void inline pln(T t, Arg ...args) {
cout << t << " ";
pln(args...);
}
template<typename T>
void inline pln(vector<T>& a, string s = " ") {
for (T& x : a) {
cout << x << s;
}
cout << endl;
}
signed main()
{
#ifndef ONLINE_JUDGE
//freopen("out.txt", "w", stdout);
#endif
ios::sync_with_stdio(0); cout.tie(0);
cin >> n;
using node = pair<int, int>;
vector<node>arr;
vector<int>dif(1e6 + 10);
int mx = 0;
int mn = INT_MAX;
rep(j, 1, n) {
int a, b;
inln(a, b);
mx = max(mx, b);
mn = min(mn, a);
dif[a]++;//差分
dif[b]--;
arr.push_back({ a,b });
}
int ans1 = 0, ans2 = 0;
int s1 = 0, s2 = 0;
rep(j, mn, mx - 1) {
if (j == 0) {
dif[j] = 1;
}
else
dif[j] += dif[j - 1];
int ok = 1;
if (dif[j] != 0) {
s1++;
s2 = 0;
}
else {
s2++;
s1 = 0;
}
ans2 = max(ans2, s2);
ans1 = max(ans1, s1);
}
pln(max(s1, ans1), max(s2, ans2));
return 0;
}