先不考虑构造字典序最小的方案,只考虑求出最小的 \(\sum\limits_{i=1}^{N-1}|A_{i+1}-A_i|\)。
设定义域为 \([L_i,R_i]\) 的函数 \(F_i(x)\) 表示考虑后缀 \([i,N]\),令 \(A_i=x\) 时上式最小的值。
初值为 \(F_N(x)=0,(x\in[L_N,R_N])\)。
显然有转移方程:
\[F_i(x)=\min\limits_{y=L_{i+1}}^{R_{i+1}}\{F_{i+1}(y)+|x-y|\} \]赛时我做到这里之后,发现是加绝对值和取 \(\min\) 的操作,便思考是否可以用类似于 Slope Trick 的方法维护之。
之后,我注意到:\(F_i(x)\) 的函数图象一定形如一段斜率为 \(-1\) 的线段、一段斜率为 \(0\) 的线段和一段斜率为 \(+1\) 的线段拼接得到的分段函数。于是,自然地,维护 \(f_i,g_i\) 表示斜率为 \(-1\) 和 \(0\) 的分界点、斜率为 \(0\) 和 \(+1\) 的分界点。
最后考虑构造出字典序最小的方案。显然 \(A_1=f_1\)。之后枚举 \(i\) 从 \(2\) 到 \(N\),若 \(A_{i-1} < L_i\),显然需要 \(A_i=L_i\);若 \(A_{i-1} > g_i\),则令 \(A_i=g_i\);否则令 \(A_i=A_{i-1}\) 即可。
// Problem: C - Jumping Through Intervals
// Contest: AtCoder - AtCoder Regular Contest 175
// URL: https://atcoder.jp/contests/arc175/tasks/arc175_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x, y, z) for(int x = (y); x <= (z); ++x)
#define per(x, y, z) for(int x = (y); x >= (z); --x)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do {freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);} while(false)
#define endl '\n'
using namespace std;
typedef long long ll;
mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
int randint(int L, int R) {
uniform_int_distribution<int> dist(L, R);
return dist(rnd);
}
template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
template<int mod>
inline unsigned int down(unsigned int x) {
return x >= mod ? x - mod : x;
}
template<int mod>
struct Modint {
unsigned int x;
Modint() = default;
Modint(unsigned int x) : x(x) {}
friend istream& operator>>(istream& in, Modint& a) {return in >> a.x;}
friend ostream& operator<<(ostream& out, Modint a) {return out << a.x;}
friend Modint operator+(Modint a, Modint b) {return down<mod>(a.x + b.x);}
friend Modint operator-(Modint a, Modint b) {return down<mod>(a.x - b.x + mod);}
friend Modint operator*(Modint a, Modint b) {return 1ULL * a.x * b.x % mod;}
friend Modint operator/(Modint a, Modint b) {return a * ~b;}
friend Modint operator^(Modint a, int b) {Modint ans = 1; for(; b; b >>= 1, a *= a) if(b & 1) ans *= a; return ans;}
friend Modint operator~(Modint a) {return a ^ (mod - 2);}
friend Modint operator-(Modint a) {return down<mod>(mod - a.x);}
friend Modint& operator+=(Modint& a, Modint b) {return a = a + b;}
friend Modint& operator-=(Modint& a, Modint b) {return a = a - b;}
friend Modint& operator*=(Modint& a, Modint b) {return a = a * b;}
friend Modint& operator/=(Modint& a, Modint b) {return a = a / b;}
friend Modint& operator^=(Modint& a, int b) {return a = a ^ b;}
friend Modint& operator++(Modint& a) {return a += 1;}
friend Modint operator++(Modint& a, int) {Modint x = a; a += 1; return x;}
friend Modint& operator--(Modint& a) {return a -= 1;}
friend Modint operator--(Modint& a, int) {Modint x = a; a -= 1; return x;}
friend bool operator==(Modint a, Modint b) {return a.x == b.x;}
friend bool operator!=(Modint a, Modint b) {return !(a == b);}
};
const ll N = 5e5 + 5, inf = 0x3f3f3f3f3f3f3f3fll;
ll n, L[N], R[N], f[N], g[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n;
rep(i, 1, n) cin >> L[i] >> R[i];
f[n] = L[n];
g[n] = R[n];
per(i, n - 1, 1) {
f[i] = f[i + 1];
g[i] = g[i + 1];
chkmax(f[i], L[i]);
chkmax(g[i], L[i]);
chkmin(f[i], R[i]);
chkmin(g[i], R[i]);
}
// rep(i, 1, n) cout << f[i] << " " << g[i] << endl;
ll val = f[1];
cout << val << " ";
rep(i, 1, n - 1) {
if(val < L[i + 1]) {
val = L[i + 1];
}
else if(val > g[i + 1]) {
val = g[i + 1];
}
cout << val << " \n"[i == n - 1];
}
return 0;
}
标签:return,int,题解,Intervals,Jumping,operator,Modint,friend,mod
From: https://www.cnblogs.com/ruierqwq/p/18105654/arc175c