Loading

线性规划做法

尝试写成线性规划的形式。

先判无解:前缀和都要 \(\le 0\),否则无解。

原问题为:

\[\min\left(\sum_{1 \le l \le r \le n} c_{l,r}\right)\quad \text{s.t.} \\ \begin{cases} \forall 1 \le i \le n, \sum\limits_{l \le i \le r} c_{l,r} w(l, i) \ge a_i \\ \forall 1 \le i \le n, \sum\limits_{l \le i \le r} -c_{l,r} w(l, i) \ge a_i \\ \forall 1 \le l \le r \le n, c_{l,r} \ge 0 \end{cases} \]

将前两个问题的变量设为 \(s, t\),对偶一下得到:

\[\max \left(\sum_{1 \le i \le n}(s_i - t_i) a_i\right)\quad \text{s.t.} \\ \begin{cases} \forall 1 \le l \le r \le n, \sum\limits_{l \le i \le r} (s_i - t_i) w_{l,i} \le 1 \\ \forall 1 \le i \le n, s_i \ge 0 \\ \forall 1 \le i \le n, t_i \ge 0 \end{cases}\]

好啊,我们记 \(b_i = s_i - t_i\),形式就变得美丽起来了。

\[\max \left(\sum_{1 \le i \le n}a_ib_i\right)\quad \text{s.t.} \\ \forall 1 \le l \le r \le n, \sum_{l \le i \le r} b_i w(l, i) \le 1\]

但是好像没有变得更简单啊?别急!

如果 \(b_i \ge 2\),则当 \(l = r = i\) 时不满足,故 \(b_i \le 1\)

如果 \(b_i \le -3\),则当 \(l = i - 1, r = i\) 时不满足。\(i = 1\) 时,注意到如果有解则 \(a_1 \ge 0\),因此此时不优。故 \(b_i \ge -2\)

我们要维护后缀最大值,发现每次会和 \(0\)\(\max\),再分析一下发现 \(\le 3\)。于是就可以直接 DP 了。

复杂度 \(O(n)\)

// code by adam01
#include<bits/stdc++.h>
using namespace std;
#define rep(i, s, t) for(int i = (int)(s); i <= (int)(t); i ++)
#define per(i, s, t) for(int i = (int)(s); i >= (int)(t); i --)
template<typename T, typename T2>
inline void chmin(T &x, T2 &&y) { x = min(x, y); }
template<typename T, typename T2>
inline void chmax(T &x, T2 &&y) { x = max(x, y); }
typedef long long ll;

const int N = 3e4 + 5;
int n;
ll a[N];
ll f[N][3][3][3];

int w(int l, int r)
{
    int k = r - l;
    if(k % 3 == 0) return 1;
    if(k % 3 == 1) return -1;
    return 0;
}

void solve()
{
    rep(i, 1, n) cin >> a[i];
    
    ll s = 0; rep(i, 1, n)
    {
        s += a[i];
        if(s > 0) return cout << -1 << "\n", void();
    }

    memset(f, -0x3f, sizeof f);
	f[0][1][1][1] = 0;
	rep(i, 1, n)
	{
		rep(j, 0, 2) rep(k, 0, 2) rep(w, 0, 2) if(f[i - 1][j][k][w] > -1e18)
		rep(b, -1, 2)
		{
			int j2 = max(j, 1) + (-b);
			int w2 = w - (-b);
			if(j2 >= 0 && w2 >= 0 && j2 <= 2 && w2 <= 2)
				chmax(f[i][k][w2][j2], f[i - 1][j][k][w] + b * a[i]);
		}
	}
	cout << *max_element((ll*)f[n], (ll*)f[n] + sizeof(f[n]) / sizeof(f[n][0][0][0])) << "\n";
}

signed main()
{
	#define fio(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout)
	fio(trans);
    ios::sync_with_stdio(0);cin.tie(0);
    int t;cin >> t >> n;while(t --) solve();

    return 0;
}
posted @ 2025-07-03 21:03  HaHeHyt  阅读(16)  评论(0)    收藏  举报