CF1031D Solution
题解
易得为使序列最小,前\(k\)个经过的点一定都是\(a\),而这些经过的点中一些原本即为\(a\)不用变换,因此用\(f\)数组记录到点\((i,j)\)能经过\(a\)的最大数量。另设\(maxs\)表示只经过原本为\(a\)或变换后为\(a\)的点的最大步数,如果\(f_{i,j}+k\)(最大\(a\)数量)\(=i+j-1\)(到\((i,j)\)路径)\(=maxs\),说明\((i,j)\)处于可以为\(a\)的点中的“边缘”,再往后走就需要bfs了。
BFS:为了字典序最小,每一步到达的节点都是这一步可到达的节点中值最小的,因此需要\(pos\)记录当前节点为第\(pos\)步到达的。此外,还需要用\(mx\)记录本步可到达最小的值,而用\(mn\)记录下一步可到达的最小值,以此维护\(mx\)。这样第一次遍历到一个节点的路径一定是最优的,所以用\(vis\)数组保证每个节点只被搜索一遍。至于记录路径,用\(pre\)表示上一个转移来的节点在队列中的编号即可,此方法只可以在手动队列中使用。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
struct node {int pos,pre,x,y;} q[N*N];
int f[N][N],cnt,hd=1,tl;
int dx[3]={0,1},dy[3]={1,0};
char mp[N][N],ans[N];
bool vis[N][N];
void print()
{
while(tl!=-1)
{
ans[++cnt]=mp[q[tl].x][q[tl].y];
tl=q[tl].pre;
}
for(int i=cnt;i>=1;i--) cout<<ans[i];
}//输出路径
int main()
{
ios::sync_with_stdio(0);
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
//处理f数组
f[1][1]=(mp[1][1]=='a');
for(int i=2;i<=n;i++) f[i][1]=f[i-1][1]+(mp[i][1]=='a'),f[1][i]=f[1][i-1]+(mp[1][i]=='a');
for(int i=2;i<=n;i++)
for(int j=2;j<=n;j++) f[i][j]=max(f[i][j-1],f[i-1][j])+(mp[i][j]=='a');
//计算maxs
int maxs=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(f[i][j]+k>=i+j-1) maxs=max(maxs,i+j-1);
for(int i=1;i<=maxs;i++) cout<<'a';
//特判
if(maxs==2*n-1) return 0;
if(n==1) {cout<<mp[1][1]; return 0;}
//寻找"边缘"节点,使它们可以到达的节点入队
int mn='z'+1,mx;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(j+i-1!=maxs || f[i][j]+k!=maxs) continue;
for(int d=0;d<2;d++)
{
int tx=i+dx[d],ty=j+dy[d];
if(tx>n || ty>n || mp[tx][ty]>mn || vis[tx][ty]) continue;
mn=mp[tx][ty]; vis[tx][ty]=1;
q[++tl]=(node){1,-1,tx,ty};
if(tx==n && ty==n) {print(); return 0;}
}
}
}
if(!maxs) q[++tl]=(node){1,-1,1,1};
//BFS
while(hd<=tl)
{
int ps=q[hd].pos,x=q[hd].x,y=q[hd].y;
if(ps==q[hd-1].pos+1) {mx=mn; mn='z'+1;}
if(mp[x][y]>mx) {hd++; continue;}
for(int i=0;i<2;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if(tx>n || ty>n || mp[tx][ty]>mn || vis[tx][ty]) continue;
mn=mp[tx][ty]; vis[tx][ty]=1;
q[++tl]=(node){ps+1,hd,tx,ty};
if(tx==n && ty==n) {print(); return 0;}
}
hd++;
}
return 0;
}