文章目录
- 传送门
- 题目大意
- 题解
- 参考代码
传送门
https://ac.nowcoder.com/acm/contest/62977/K
题目大意
给定一个 n × m n \times m n×m 的矩阵 G G G ,每个点有权值 G i , j G_{i,j} Gi,j,开始可以选择一个方向跳,每次跳跃只能跳到严格大于当前点权的位置。跳跃过程中总共可以转一次方向,求最多可以跳几次。
题解
不妨枚举它的转弯点和它的方向,
例如,从上方来到转弯点,
它可以选择往左或往右跳(或者往前跳,即放弃转弯机会)。
剩下的就是单向操作了,可以预处理。
问题转化为了如何处理一行或一列的最长单调 下降/上升 子序列。
对于这个问题,要求
n
l
o
g
n
n logn
nlogn 或
n
n
n \sqrt n
nn 解决,考虑优化。
理想的,有一条优秀的序列,将它直接插入该序列中,查找比它小的个数就可以得到最大的解。
显然的,该序列是单调的,且需要有尽可能多的数,在满足单调性的同时,我们要使两两差尽可能小。
故每次维护只需要把一个大于或等于当前权值的数代替即可。如果大于顶部元素,直接加入即可。
对于这个问题,跑
8
8
8 次查询就可以维护好了。
参考代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,T;
int st[N];
int ans;
int main()
{
cin>>T;
while(T--)
{
ans=0;
scanf("%d%d",&n,&m);
vector<vector<int>>v(n+1,vector<int>(m+1));
vector<vector<int>>v1(n+1,vector<int>(m+1)); //横着从左往右递增
vector<vector<int>>v2(n+1,vector<int>(m+1)); //横着从右往左递增
vector<vector<int>>v3(n+1,vector<int>(m+1)); //横着从左往右递减
vector<vector<int>>v4(n+1,vector<int>(m+1)); //横着从右往左递减
vector<vector<int>>v5(n+1,vector<int>(m+1)); //横着从下往上递增
vector<vector<int>>v6(n+1,vector<int>(m+1)); //横着从上往下递增
vector<vector<int>>v7(n+1,vector<int>(m+1)); //横着从下往上递减
vector<vector<int>>v8(n+1,vector<int>(m+1)); //横着从上往下递减
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&v[i][j]);
for(int i=1;i<=n;i++)
{
int tot=0;
st[tot]=0;
for(int j=1;j<=m;j++)
{
if(v[i][j]>st[tot])
{
st[++tot]=v[i][j];
v1[i][j]=tot-1;
}
else
{
int id=lower_bound(st+1,st+tot+1,v[i][j])-st;
st[id]=v[i][j];
v1[i][j]=id-1;
}
}
}
for(int i=1;i<=n;i++)
{
int tot=0;
st[tot]=-N;
for(int j=1;j<=m;j++)
{
if(-v[i][j]>st[tot])
{
st[++tot]=-v[i][j];
v3[i][j]=tot-1;
}
else
{
int id=lower_bound(st+1,st+tot+1,-v[i][j])-st;
st[id]=-v[i][j];
v3[i][j]=id-1;
}
}
}
for(int i=1;i<=n;i++)
{
int tot=0;
st[tot]=0;
for(int j=m;j>=1;j--)
{
if(v[i][j]>st[tot])
{
st[++tot]=v[i][j];
v2[i][j]=tot-1;
}
else
{
int id=lower_bound(st+1,st+tot+1,v[i][j])-st;
st[id]=v[i][j];
v2[i][j]=id-1;
}
}
}
for(int i=1;i<=n;i++)
{
int tot=0;
st[tot]=-N;
for(int j=m;j>=1;j--)
{
if(-v[i][j]>st[tot])
{
st[++tot]=-v[i][j];
v4[i][j]=tot-1;
}
else
{
int id=lower_bound(st+1,st+tot+1,-v[i][j])-st;
st[id]=-v[i][j];
v4[i][j]=id-1;
}
}
}
for(int i=1;i<=m;i++)
{
int tot=0;
st[tot]=0;
for(int j=1;j<=n;j++)
{
if(v[j][i]>st[tot])
{
st[++tot]=v[j][i];
v5[j][i]=tot-1;
}
else
{
int id=lower_bound(st+1,st+tot+1,v[j][i])-st;
st[id]=v[j][i];
v5[j][i]=id-1;
}
}
}
for(int i=1;i<=m;i++)
{
int tot=0;
st[tot]=-N;
for(int j=1;j<=n;j++)
{
if(-v[j][i]>st[tot])
{
st[++tot]=-v[j][i];
v7[j][i]=tot-1;
}
else
{
int id=lower_bound(st+1,st+tot+1,-v[j][i])-st;
st[id]=-v[j][i];
v7[j][i]=id-1;
}
}
}
for(int i=1;i<=m;i++)
{
int tot=0;
st[tot]=0;
for(int j=n;j>=1;j--)
{
if(v[j][i]>st[tot])
{
st[++tot]=v[j][i];
v6[j][i]=tot-1;
}
else
{
int id=lower_bound(st+1,st+tot+1,v[j][i])-st;
st[id]=v[j][i];
v6[j][i]=id-1;
}
}
}
for(int i=1;i<=m;i++)
{
int tot=0;
st[tot]=-N;
for(int j=n;j>=1;j--)
{
if(-v[j][i]>st[tot])
{
st[++tot]=-v[j][i];
v8[j][i]=tot-1;
}
else
{
int id=lower_bound(st+1,st+tot+1,-v[j][i])-st;
st[id]=-v[j][i];
v8[j][i]=id-1;
}
}
}
// cout<<v1[2][4]<<" "<<v2[2][4]<<" "<<v3[2][4]<<" "<<v4[2][4]<<"\n";
// cout<<v5[2][4]<<" "<<v6[2][4]<<" "<<v7[2][4]<<" "<<v8[2][4]<<"\n";
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
// cout<<v1[i][j]<<" "<<v2[i][j]<<" "<<v3[i][j]<<" "<<v4[i][j]<<endl;
int sum=0;
sum =max(sum,max(v1[i][j]+v7[i][j],
max(v1[i][j]+v8[i][j],
max(v2[i][j]+v7[i][j],
max(v2[i][j]+v8[i][j],
max(v5[i][j]+v3[i][j],
max(v5[i][j]+v4[i][j],
max(v6[i][j]+v3[i][j],
max(v6[i][j]+v4[i][j],
max(v1[i][j]+v4[i][j],
max(v2[i][j]+v3[i][j],
max(v5[i][j]+v8[i][j],
v6[i][j]+v7[i][j])
)
)
)
)
)
)
)
)
)
)
)+1;
if(sum>ans)
{
ans=sum;
// cout<<i<<" "<<j<<endl;
// cout<<sum<<endl;
}
}
printf("%d\n",ans);
}
}