【題解】[USACO13FEB]Tractor S
阿新 • • 發佈:2020-09-17
\(\text{Solution:}\)
好久沒寫啥\(dfs\)了,借這個題整理下細節。
觀察到答案具有二分性,所以先求出其差的最大最小值,\(\log val\)的複雜度不成問題。
考慮如何\(check:\)
考慮一個\(dfs\)預處理當前點為\((i,j),\)高度為\(k\)所能到達的所有點。這一步是\(n^2\)的複雜度。注意判斷是否出界的時候符號不要打反,以及這題所謂高度差是在絕對值意義上的。
遍歷變數時不要重名。
於是,這題可以在\(O(n^2\log m)\)的複雜度完成。
還有一個想法是求出原樹的最小生成樹後處理出\(siz\)和子樹的最大差。然後可以\((n^2\log n^2)\)
#include<bits/stdc++.h> using namespace std; const int MAXN=5e5+10; int a[501][501],n; const int dx[4]={1,0,-1,0}; const int dy[4]={0,1,0,-1}; int L,R,ans,vis[501][501]; int dfs(int x,int y,int kk){ int cnt=1; vis[x][y]=1; for(int k=0;k<4;++k){ int nx=x+dx[k],ny=y+dy[k]; if(nx<1||ny<1||nx>n||ny>n||vis[nx][ny]||abs(a[x][y]-a[nx][ny])>kk)continue; cnt+=dfs(nx,ny,kk); } return cnt; } bool check(int k){ memset(vis,0,sizeof vis); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j){ if(vis[i][j])continue; int C=dfs(i,j,k); if(C*2>=n*n)return true; } return false; } int main(){ scanf("%d",&n); L=(1<<30);R=-L; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&a[i][j]); for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ for(int k=0;k<4;++k){ int x=i+dx[k],y=j+dy[k]; R=max(R,a[i][j]-a[x][y]); L=min(L,a[i][j]-a[x][y]); } } } while(L<=R){ int mid=L+R>>1; if(check(mid))ans=mid,R=mid-1; else L=mid+1; } printf("%d\n",ans); return 0; }