题解 ARC175C【Jumping Through Intervals】

先不考虑构造字典序最小的方案,只考虑求出最小的 \(\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;
}
posted @ 2024-03-30 16:15  rui_er  阅读(63)  评论(0编辑  收藏  举报