Luogu 1514 [NOIP2010] 引水入城
我就是过来开心一下……这道题从开坑以来已经堆积了大半年了……今天才发现广搜一直写挂……
丢个线段覆盖的模板,设$f_{i}$表示覆盖区间[1, i]的最小代价,$g_{i, j}$表示覆盖区间[i, j]的代价,有转移方程
$f_{i} = f_{j} + g_{j + 1, i}$ $(0 < j < i)$
这道题直接暴力跑转移就可以了,但是对于一些n比较大的题,可以写一个前向星或者是vector存右端点一样的线段,这样子会快很多
还有要注意n = 1的坑点
放个提交记录给自己警示一下!https://www.luogu.org/recordnew/lists?uid=60553&pid=1514
Code:
#include <cstdio> #include <queue> #include <cstring> using namespace std; const int N = 505; const int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, 1, -1}; const int inf = 0x3f3f3f3f; int n, m, a[N][N], f[N], g[N][N], ran[N][2], tot = 0, head[N]; bool cov[N], vis[N], vis2[N][N]; struct Segment { int ln, nxt; } s[N]; inline void add(int ln, int rn) { s[++tot].ln = ln; s[tot].nxt = head[rn]; head[rn] = tot; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline int max(int x, int y) { return x > y ? x : y; } inline int min(int x, int y) { return x > y ? y : x; } struct Node { int x, y; }; queue <Node> Q; inline bool vivid(Node now) { return now.x >= 1 && now.x <= n && now.y >= 1 && now.y <= m; } void bfs(int fir) { memset(vis2, 0, sizeof(vis2)); vis2[1][fir] = 1; int ln = inf, rn = -inf; Q.push((Node) {1, fir}); if(n == 1) { cov[fir] = 1; ln = rn = fir; } vis[fir] = 1; for(; !Q.empty(); ) { Node out = Q.front(); Q.pop(); for(int i = 0; i < 4; i++) { Node in = (Node) {out.x + dx[i], out.y + dy[i]}; if(vivid(in) && a[out.x][out.y] > a[in.x][in.y] && !vis2[in.x][in.y]) { if(in.x == 1) vis[in.y] = 1; if(in.x == n) { cov[in.y] = 1; ln = min(ln, in.y); rn = max(rn, in.y); } vis2[in.x][in.y] = 1; Q.push(in); } } } // printf("%d %d %d\n", fir, ln, rn); if(ln > rn) return; for(int i = ln; i <= rn; i++) { for(int j = i; j <= rn; j++) { g[i][j] = 1; if(i == 1) f[j] = 1; } } } int main() { // freopen("1.in", "r", stdin); read(n), read(m); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) read(a[i][j]); memset(g, 0x3f, sizeof(g)); memset(f, 0x3f, sizeof(f)); for(int i = 1; i <= m; i++) if(!vis[i]) bfs(i); int cnt = 0; for(int i = 1; i <= m; i++) if(!cov[i]) cnt++; if(cnt > 0) { printf("0\n%d\n", cnt); return 0; } /* for(int i = 1; i <= m; i++) printf("%d ", f[i]); printf("\n"); */ for(int i = 1; i <= m; i++) for(int j = 1; j <= i; j++) f[i] = min(f[i], f[j] + g[j + 1][i]); printf("1\n%d\n", f[m]); return 0; }