KM 做法這麼簡單好想為什麼都在 dp?我第一次過也是用的 dp。
建模非常好想,每天只能收一次錢,最簡單的思路是我們列舉第幾天開車跑路,但是再一想我們不關心是第幾天,只關心每次貸款離開車跑路還差幾天,於是我們從 \(i\) 向 \(j\) 連邊,邊權是 \(a_i+b_i\times\min(k_i,j)\),意義為第 \(i\) 種貸款離買車還差 \(j\) 天對答案的貢獻,當然我們實現時需要對 \(0\) 取最大值,因為取 \(0\) 的意義為不參與答案貢獻,然而我們並不要求在最後一天開車,所以對 \(0\) 取最大值是必要的。
並且,容易證明我們不可能在某一天沒有進行任何操作。
所以建完模直接跑 KM 演算法即可,時間複雜度 \(\mathcal{O(n^3)}\)。
程式碼:
#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define eb emplace_back
#define inf 1000000000
#define linf 10000000000000000
#define pii pair <int, int>
using namespace std;
constexpr int N = 505, P = 1e9 + 7;
inline int rd ()
{
int x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) { if (ch == '-') f = -1; ch = getchar (); }
while (isdigit (ch)) { x = (x << 1) + (x << 3) + ch - 48; ch = getchar (); }
return x * f;
}
int n, sum, ans;
int e[N][N];
int lx[N], ly[N], px[N], py[N], pre[N], slack[N];
bool vx[N], vy[N], flag;
int a[N], b[N], k[N];
queue <int> q;
void aug (int v)
{
while (v)
{
int t = px[pre[v]];
px[pre[v]] = v;
py[v] = pre[v];
v = t;
}
}
void bfs (int s)
{
memset (vx, 0, sizeof vx);
memset (vy, 0, sizeof vy);
memset (slack, 127, sizeof slack);
while (! q.empty ()) q.pop ();
q.push (s);
while (true)
{
while (! q.empty ())
{
int u = q.front ();
q.pop ();
vx[u] = 1;
rep (i, 1, n)
{
if (vy[i]) continue;
if (lx[u] + ly[i] - e[u][i] < slack[i])
{
slack[i] = lx[u] + ly[i] - e[u][i];
pre[i] = u;
if(! slack[i])
{
vy[i] = 1;
if (! py[i])
{
aug (i); return ;
} else q.push (py[i]);
}
}
}
}
int d = linf;
rep (i, 1, n) if (! vy[i]) d = min (d, slack[i]);
rep (i, 1, n)
{
if (vx[i]) lx[i] -= d, sum -= d;
if (vy[i]) ly[i] += d, sum += d;
else slack[i] -= d;
}
rep (i, 1, n)
{
if (vy[i]) continue;
if(! slack[i])
{
vy[i] = 1;
if (! py[i])
{
aug (i); return ;
} else q.push (py[i]);
}
}
}
}
void solve ()
{
memset (lx, -127, sizeof lx);
sum = 0;
rep (i, 1, n) rep (j, 1, n) lx[i] = max (lx[i], e[i][j]);
rep (i, 1, n) sum += lx[i];
rep (i, 1, n)
bfs (i);
}
signed main ()
{
n = rd ();
rep (i, 1, n)
{
a[i] = rd (), b[i] = rd (), k[i] = rd ();
}
rep (i, 1, n)
rep (j, 1, n)
e[i][j] = max (0ll, a[i] - min (k[i], j - 1) * b[i]);
solve ();
printf ("%lld\n", sum);
}
/*
*/