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;
}

参考博客

posted @ 2021-01-10 10:21  violet_holmes  阅读(59)  评论(0编辑  收藏  举报