线性规划做法
尝试写成线性规划的形式。
先判无解:前缀和都要 \(\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;
}

浙公网安备 33010602011771号