每个第一行的城市,在最后一列能影响到的一定是一段连续区间。如果不连续,假设是两段区间,那么两段区间中肯定不能被其他第一行的城市影响到,如果影响到,如下图
如果蓝色和红色相交,那么蓝色一定可以更新到红色的。所以假设是两段区间,那么两段区间中肯定不能被其他第一行的城市影响到,而这种情况就是题目所谓不合法情况。
那么我们就记忆化搜索,把第一行每个城市能影响到的最后一行的连续区间大小处理出来。
然后就是求一个区间完全覆盖问题。
按左端点排序,贪心思想,每次选左端点在已覆盖区间内,右端点最远的。
shang:目前已经覆盖到的区间的最右边。
now:剩下的线段中左端点在shang的左边或和shang一起的线段的右端点的最大值。
注意啊!我们的区间看成右开左闭,shang从0开始,就当作背个板子吧~~~~~。。。。。=。=
#include
using namespace std;
int n,m,a[595][595],vis[595][595],l[595][595],r[595][595];
int zl[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
struct node
{
int l,r;
};
node q[595];
void read(int &x)
{
x = 0; int f = 0; char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = 1; c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0'; c = getchar();
}
if(f) x = -x ;
}
bool cmp(const node a,const node b)
{
return a.l < b.l;
}
void dfs(int x,int y)
{
if(vis[x][y]) return;
vis[x][y] = 1;
for(int k = 0; k <= 3; k++)
{
int xx = x + zl[k][0];
int yy = y + zl[k][1];
if(xx >= 1 && xx <= n && yy >= 1 && yy <= m&&a[xx][yy] < a[x][y])
{
if(vis[xx][yy] == 0) dfs(xx,yy);
l[x][y] = min(l[xx][yy],l[x][y]);
r[x][y] = max(r[x][y],r[xx][yy]);
}
}
}
int main()
{
//freopen("ha.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(vis,0,sizeof(vis));
memset(l,0x3f3f3f3f,sizeof(l));
for(int i = 1; i <= m; i++)
l[n][i] = r[n][i] = i;
for(int i = 1; i <= m; i++)
dfs(1,i);
int cnt = 0;
for(int i = 1; i <= m; i++)
if(vis[n][i] == 0) cnt++;
if(cnt)
{
printf("0\n"); printf("%d",cnt);return 0;
}
printf("1\n");
for(int i = 1; i <= m; i++)
{
if(r[1][i]){cnt++;
q[cnt].l = l[1][i] - 1; q[cnt].r = r[1][i];
}
}
sort(q+1,q+1+cnt,cmp);
int now = 0;
int ans = 0,shang = 0;
for(int i = 1; i <= cnt; i++)
{
if(q[i].l > shang){ans++,shang = now;
}
now = max(now,q[i].r);
}
if(shang < m)ans++;
cout << ans;
return 0;
}