T3 网格游走
- 本质上是一道trajan构图+floodfill+期望的壳子
- 对于高度来说,我们自然需要重新建图:-》知识点:二维变成一维的图
return (x-1)*m+y
- 那么新图就建出来了:同时我们可以考虑(现在这个图是DAG吗?显然不是,那么我们往往特殊走:如果一块之间是DAG我们会怎么处理)
- 如果是DAG的话,我们显然可以从多个入度为0(对于DAG一定要关注入度或者出度为0的点)进入队列,然后用floodfill的思想从多个角度top序更新
- 那么:怎么样才能够锁点?:
- trajan缩完点之后,我们要关注的是缩完点之后的点的性质:以本题为例,缩完之后的点贡献期望是多少
- 这时候需要根据期望的递推式进行记忆化搜搜:
最后一定要关注一个东西:用暴力求解得出来的答案可以尝试打表一下观察他们的特殊性:本题 fi=2i
- 代码:
-
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define ll long long using namespace std; inline int read() { int s=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();} return s*f; } const int N=3e6+1,M=3e6+1,L=1e6+1; struct Edge { int nxt,to; void make(int _nxt,int _to){nxt=_nxt;to=_to;} }edge1[2*M+1],edge2[2*M+1]; int edge1_tot,edge2_tot,head1[N],head2[N]; void edge1_add(int x,int y){edge1[++edge1_tot].make(head1[x],y);head1[x]=edge1_tot;} void edge2_add(int x,int y){edge2[++edge2_tot].make(head2[x],y);head2[x]=edge2_tot;} int n,m,tim,dfn[N],low[N],stc[N],top,color,co[N],dd[N];ll dis[N],f[1000001],v[1000001]; int change(int x,int y){return (x-1)*m+y;} void tarjan(int u) { dfn[u]=low[u]=++tim; stc[++top]=u; for(int i=head1[u];i;i=edge1[i].nxt) { int v=edge1[i].to; if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);} else if(!co[v])low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { co[u]=++color; dis[color]=v[u];dd[color]=1; while(stc[top]!=u) { co[stc[top]]=color; dis[color]+=v[stc[top]]; dd[color]++; top--; } top--; } } struct node { int x,y,op; void make(int _x,int _y,int _op){x=_x;y=_y;op=_op;} }dian[N]; int h[1001][1001],dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1},du[1000001]; int main() { freopen("road.in","r",stdin); freopen("road.out","w",stdout); n=read(),m=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) h[i][j]=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) v[change(i,j)]=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { for(int k=1;k<=4;k++) { int x=i+dx[k],y=j+dy[k]; if(x<=0||y<=0||x>n||y>m)continue; int k1=change(i,j),k2=change(x,y); if(h[i][j]<h[x][y])swap(k1,k2); edge1_add(k1,k2); } } for(int i=1;i<=n*m;i++)if(!dfn[i])tarjan(i); for(int i=1;i<=n*m;i++) for(int j=head1[i];j;j=edge1[j].nxt) { int v=edge1[j].to; if(co[i]==co[v])continue; edge2_add(co[i],co[v]); du[co[v]]++; } queue<int>q;ll ans=0; for(int i=1;i<=color;i++) { if(!du[i])q.push(i); // printf("%lld\n",dis[i]); } while(!q.empty()) { int u=q.front();q.pop(); if(dd[u]!=1)f[u]+=2ll*dis[u]; else f[u]+=dis[u]; ans=max(ans,f[u]); for(int i=head2[u];i;i=edge2[i].nxt) { int v=edge2[i].to; if(!--du[v])q.push(v); f[v]=max(f[v],f[u]); } } printf("%lld\n",ans); return 0; }
- fread优化:
View Code#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <cctype> using namespace std; const int S = 1 << 20; char frd[S], *hed = frd + S; const char *tal = hed; inline char nxtChar() { if (hed == tal) fread(frd, 1, S, stdin), hed = frd; return *hed++; } template <class T> inline void read(T &res) { char ch; while (ch = nxtChar(), !isdigit(ch)); res = ch ^ 48; while (ch = nxtChar(), isdigit(ch)) res = res * 10 + ch - 48; } typedef long long ll; const int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1}; const int N = 1005, M = 1e6 + 5; int h[N][N], v[N][N], num[N][N], rin[M]; int dfn[M], low[M], stk[M], col[M], point[M], val[M]; ll f[M], unt[M], ans; int n, m, G, C, top, tis; bool inv[M]; struct Edge { int to; Edge *nxt; }; struct Graph { Edge p[M << 2], *lst[M], *P; inline void Init() { P = p; } inline void addEdge(int x, int y) { (++P)->nxt = lst[x]; lst[x] = P; P->to = y; } }newG, oldG; inline bool check(int x, int y) { return x >= 1 && x <= n && y >= 1 && y <= m; } template <class T> inline void CkMin(T &x, T y) {if (x > y) x = y;} template <class T> inline void CkMax(T &x, T y) {if (x < y) x = y;} inline void Tarjan(int x) { dfn[x] = low[x] = ++tis; int y; stk[++top] = x; inv[x] = true; for (Edge *e = oldG.lst[x]; e; e = e->nxt) if (!dfn[y = e->to]) Tarjan(y), CkMin(low[x], low[y]); else if (inv[y]) CkMin(low[x], dfn[y]); if (dfn[x] == low[x]) { inv[x] = false; col[x] = ++C; point[C] = 1; unt[C] = val[x]; while (y = stk[top--], y != x) inv[y] = false, col[y] = C, unt[C] += val[y], ++point[C]; } } int main() { freopen("road.in", "r", stdin); freopen("road.out", "w", stdout); oldG.Init(); newG.Init(); read(n); read(m); for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) read(h[i][j]); for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) read(v[i][j]); for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) num[i][j] = ++G, val[G] = v[i][j]; for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) for (int k = 0; k < 4; ++k) { int tx = i + dx[k], ty = j + dy[k]; if (check(tx, ty) && h[tx][ty] <= h[i][j]) oldG.addEdge(num[i][j], num[tx][ty]); } for (int i = 1; i <= G; ++i) if (!dfn[i]) Tarjan(i); for (int i = 1; i <= C; ++i) if (point[i] > 1) unt[i] = unt[i] << 1ll; for (int i = 1; i <= G; ++i) for (Edge *e = oldG.lst[i]; e; e = e->nxt) { int y = e->to; if (col[i] == col[y]) continue; newG.addEdge(col[i], col[y]); ++rin[col[y]]; } for (int i = 1; i <= C; ++i) if (!rin[i]) stk[++top] = i, f[i] = unt[i]; int x, y; while (top) { x = stk[top--]; for (Edge *e = newG.lst[x]; e; e = e->nxt) { if (!--rin[y = e->to]) stk[++top] = y; CkMax(f[y], f[x] + unt[y]); } } for (int i = 1; i <= C; ++i) CkMax(ans, f[i]); cout << ans << endl; }


浙公网安备 33010602011771号