Abstract
傳送門
Idea
顯然是一個差分約束系統。不妨用 dist[i] 表示前 i 個位置種的樹的數目,那麼,容易得出下列方程:
- dist[i] >= dist[i-1]
- dist[i] - dist[i-1] <= 1 (每個位置至多能種一顆樹)
題目要求 b 到 e 之間至少種 t 棵樹,其數學形式就是:
- dist[b] - dist[e-1] >= t
依據上面三種方程,我們構建了一個完整的差分約束系統,接下來跑最短路求出 dist 陣列的一個可能取值就行了。然後,考慮到邊界條件 dist[0] = 0,所以答案是 dist[n] - dist[0] 。
Code
#include <bits/stdc++.h>
using namespace std;
int n, h;
namespace graph
{
const int maxn = 100000;
int head[maxn];
int cnt;
struct Edge
{
int next, to, value;
} edge[maxn];
void add(int u, int v, int c)
{
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].value = c;
head[u] = cnt;
return;
}
};
bool SPFA(int start, int dist[])
{
queue<int> q;
bool inQueue[graph::maxn] = {false};
int count[graph::maxn] = {0};
for (int i = 1; i < n + 1; i++)
{
dist[i] = 0x3f3f3f3f;
}
dist[start] = 0;
q.push(start);
inQueue[start] = true;
count[start] = 1;
while (!q.empty())
{
int u = q.front();
q.pop();
inQueue[u] = false;
for (int i = graph::head[u]; i; i = graph::edge[i].next)
{
int v = graph::edge[i].to;
int w = graph::edge[i].value;
if (dist[u] + w < dist[v])
{
dist[v] = dist[u] + w;
if (!inQueue[v])
{
q.push(v);
inQueue[v] = true;
count[v]++;
}
if (count[v] > n + 1)
{
return true;
}
}
}
}
return false;
}
void solve()
{
cin >> n >> h;
for (int i = 0; i < h; i++)
{
int e, b, t;
cin >> b >> e >> t;
graph::add(e, b - 1, -t);
}
for (int i = 0; i < n; i++)
{
graph::add(i, i + 1, 1);
graph::add(i + 1, i, 0);
}
for (int i = 0; i < n + 1; i++)
{
graph::add(n + 1, i, 0);
}
int dist[graph::maxn];
SPFA(n + 1, dist);
cout << dist[n] - dist[0];
return;
}
signed main()
{
int t = 1;
while (t--)
{
solve();
}
return 0;
}