【Codeforces Round #517 (Div. 2, based on Technocup 2019 Elimination Round 2) D. Minimum path】dp+滚动数组


D. Minimum path

题意

给你一个字符矩阵,起点在左上角,每次可以向右或者向下走,可以改变这个字符矩阵中的k个字符,是这个路径构成的字符串字典序最小。

做法

由于可以改变k个字符,那么肯定是找到一条路径,前面至少有k项为a,
后面按照字典序选择路径就可以。
所以我们先用dp[i][j]表示从原点到(i,j)的路径中a最多有多少个。
之后对所有dp[i][j]-(i+j-1)>=k的点中选一个(i+j-1)最大的,
也就是能让前缀全是a的最长前缀,然后把所有满足的丢进vector
用滚动的vector每次选出往后走的字典序最小的,再丢尽vector
对每个点存一下他的上一个点,pre[i][j]
走到最后vector的大小为1,也就是走到终点,
最后通过pre[i][j]逆序输出答案

代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
const int maxn = 2005;
int n,k,dp[maxn][maxn];
int vis[maxn][maxn];
pii mp[maxn][maxn];
char pic[maxn][maxn];
vector<pii> ans[2];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",pic[i]+1);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(pic[i][j]=='a')
            {
                dp[i][j]=max(dp[i-1][j],dp[i][j-1])+1;
            }
            else
            {
                 dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
    }
    k=min(k,2*n-1);
    int maxx=k;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(dp[i][j]>=(i+j-1)-k) maxx=max(maxx,i+j-1);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
             if(dp[i][j]>=(i+j-1)-k&&(i+j-1)==maxx)
             {
                 ans[0].push_back(pii(i,j));
             }
        }
    }
    string tmp="";
    for(int i=1;i<=maxx;i++) tmp+='a';
    int left;
    if(tmp=="")
    {
        left=2*n-2;
        ans[0].push_back(pii(1,1));
    }
    else
    {
        left=2*n-1-maxx;
    }
    for(int i=0;i<left;i++)
    {
        int minn=25;
        for(int j=0;j<ans[i%2].size();j++)
        {
            int stx=ans[i%2][j].first;
            int sty=ans[i%2][j].second;
            if(stx<n) minn=min(minn,pic[stx+1][sty]-'a');
            if(sty<n) minn=min(minn,pic[stx][sty+1]-'a');
        }
        ans[(i+1)%2].clear();
        for(int j=0;j<ans[i%2].size();j++)
        {
            int stx=ans[i%2][j].first;
            int sty=ans[i%2][j].second;
            if(stx<n)
            {
                if(pic[stx+1][sty]-'a'==minn&&!vis[stx+1][sty])
                {
                    vis[stx+1][sty]=1;
                    mp[stx+1][sty]=pii(stx,sty);
                    ans[(i+1)%2].push_back(pii(stx+1,sty));
                }
            }
            if(sty<n)
            {
                if(pic[stx][sty+1]-'a'==minn&&!vis[stx][sty+1])
                {
                    vis[stx][sty+1]=1;
                    mp[stx][sty+1]=pii(stx,sty);
                    ans[(i+1)%2].push_back(pii(stx,sty+1));
                }
            }
        }
    }
    string ans="";
    int sx=n,sy=n;
    while(sx+sy-1>maxx)
    {
        ans+=pic[sx][sy];
        pii tmp=mp[sx][sy];
        sx=tmp.first;
        sy=tmp.second;
    }
    reverse(ans.begin(),ans.end());
    tmp+=ans;
    printf("%s\n",tmp.c_str());
    return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_38891827/article/details/84559357