传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3205
【题解】
我们发现这就是一棵斯坦纳树啊。。
令f[l,r,a,b]表示合并了(l,r),当前在(a,b)的最小推的次数。
预处理出来每个点朝每个方向推一下到哪里。(dfs,注意处理循环情况)
然后我们就可以套斯坦纳树板子了。
但是发现过不了。。因为spfa好像复杂度不对?
由于spfa边权都是1,所以我们用bfs来扩展。
我们把原有的节点按照f值排序,然后维护一个栈来存储原有的节点,用一个队列存储扩展的节点。
容易发现这两个里面都是单调的。每次比较头即可。
然后复杂度对了。。注意要基数排序(?)
然后基数排序数组要开大啊不然会RE...
大概100w?
bzoj怎么都能过系列。
# include <queue> # include <cctype> # include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 503, N = 10, F = 6e5 + 3, FF = 1e6 + 10; const int mod = 1e9+7; # define RG register # define ST static int n, W, H; char mp[M][M]; int f[N][N][M][M]; struct pa { int x, y; pa() {} pa(int x, int y) : x(x), y(y) {} friend bool operator == (pa a, pa b) { return a.x==b.x && a.y==b.y; } friend bool operator != (pa a, pa b) { return !(a==b); } }; int dfs_clock; pa dp[M][M][4]; int v[M][M][4]; // 0: up, 1: right, 2: down, 3: left const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}; inline pa dfs(int x, int y, int face) { if(v[x][y][face] == dfs_clock) return pa(-1, -1); v[x][y][face] = dfs_clock; if(dp[x][y][face] != pa(0, 0)) return dp[x][y][face]; int nface = face, nx = x, ny = y; if(mp[x][y] == 'A') nface = (nface+3)%4; if(mp[x][y] == 'C') nface = (nface+1)%4; nx += dx[nface], ny += dy[nface]; if(nx<=0 || ny<=0 || nx>H || ny>W) return dp[x][y][face] = pa(x, y); if(mp[nx][ny] == 'x') return dp[x][y][face] = pa(x, y); return dp[x][y][face] = dfs(nx, ny, nface); } pa q[F], st[F]; bool vis[M][M]; int su[FF], va[F], vn=0, stn; inline void spfa(int sti, int stj) { int head = 1, tail = 0; memset(su, 0, sizeof su); vn = 0; int mx = -1e9, mi = 1e9; for (int i=1; i<=H; ++i) for (int j=1; j<=W; ++j) if(f[sti][stj][i][j] != 1e9) { q[++tail] = pa(i, j); va[++vn] = f[sti][stj][i][j]; su[va[vn]] ++; if(va[vn] > mx) mx = va[vn]; if(va[vn] < mi) mi = va[vn]; vis[i][j] = 1; } for (int i=mi; i<=mx; ++i) su[i] += su[i-1]; for (int i=1; i<=vn; ++i) st[su[va[i]]--] = q[i]; stn = vn; reverse(st+1, st+stn+1); head = 1, tail = 0; while(head <= tail || stn) { pa t; if(head > tail) { t = st[stn]; --stn; } else if(!stn) { t = q[head]; ++head; } else { int ta = f[sti][stj][q[head].x][q[head].y], tb = f[sti][stj][st[stn].x][st[stn].y]; if(ta < tb) t = q[head], ++head; else t = st[stn], --stn; } vis[t.x][t.y] = 0; for (int i=0; i<4; ++i) { int nx = dp[t.x][t.y][i].x, ny = dp[t.x][t.y][i].y; if(nx == -1) continue; if(f[sti][stj][t.x][t.y]+1 < f[sti][stj][nx][ny]) { f[sti][stj][nx][ny] = f[sti][stj][t.x][t.y]+1; if(!vis[nx][ny]) { vis[nx][ny] = 1; q[++tail] = pa(nx, ny); } } } } } inline void debug() { for (int sti=1; sti<=n; ++sti) for (int stj=sti; stj<=n; ++stj) for (int i=1; i<=H; ++i) for (int j=1; j<=W; ++j) printf("(%d, %d) (H,W: %d, %d) %d ", sti, stj, i, j, f[sti][stj][i][j]); // system("pause"); } int main() { scanf("%d%d%d", &n, &W, &H); for (int i=1; i<=H; ++i) scanf("%s", mp[i]+1); for (int i=1; i<=H; ++i) for (int j=1; j<=W; ++j) for (int face=0; face<4; ++face) if(mp[i][j] == 'x') dp[i][j][face] = pa(-1, -1); else dp[i][j][face] = pa(0, 0); for (int i=1; i<=H; ++i) for (int j=1; j<=W; ++j) for (int face=0; face<4; ++face) { dfs_clock++; dp[i][j][face] = dfs(i, j, face); } // for (int i=1; i<=H; ++i) // for (int j=1; j<=W; ++j) // for (int face=0; face<4; ++face) // printf("i=%d, j=%d, face=%d, dp[i][j][face] = (%d, %d) ", i, j, face, dp[i][j][face].x, dp[i][j][face].y); for (int sti=1; sti<=n; ++sti) for (int stj=sti; stj<=n; ++stj) for (int i=1; i<=H; ++i) for (int j=1; j<=W; ++j) f[sti][stj][i][j] = 1e9; for (int i=1; i<=H; ++i) for (int j=1; j<=W; ++j) if(isdigit(mp[i][j])) { int t = mp[i][j] - '0'; f[t][t][i][j] = 0; } for (int len=1; len<=n; ++len) for (int sti=1; sti<=n-len+1; ++sti) { int stj = sti + len - 1; // (sti, stj) status for (int i=1; i<=H; ++i) for (int j=1; j<=W; ++j) for (int st = sti; st < stj; ++st) f[sti][stj][i][j] = min(f[sti][stj][i][j], f[sti][st][i][j] + f[st+1][stj][i][j]); spfa(sti, stj); } // debug(); int ans = 1e9; for (int i=1; i<=H; ++i) for (int j=1; j<=W; ++j) ans = min(ans, f[1][n][i][j]); printf("%d ", ans == 1e9 ? -1 : ans); return 0; }