1. 程式人生 > >Codeforces Round #517 (Div. 2, based on Technocup 2019 Elimination Round 2):D. Minimum path(思維)

Codeforces Round #517 (Div. 2, based on Technocup 2019 Elimination Round 2):D. Minimum path(思維)

D. Minimum path
time limit per test1.5 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given a matrix of size n×n filled with lowercase English letters. You can change no more than k letters in this matrix.

Consider all paths from the upper left corner to the lower right corner that move from a cell to its neighboring cell to the right or down. Each path is associated with the string that is formed by all the letters in the cells the path visits. Thus, the length of each string is 2n−1.

Find the lexicographically smallest string that can be associated with a path after changing letters in at most k cells of the matrix.

A string a is lexicographically smaller than a string b, if the first different letter in a and b is smaller in a.

Input
The first line contains two integers n and k (

1n2000,0kn2)(1≤n≤2000, 0≤k≤n^2) — the size of the matrix and the number of letters you can change.

Each of the next n lines contains a string of n lowercase English letters denoting one row of the matrix.

Output
Output the lexicographically smallest string that can be associated with some valid path after changing no more than k letters in the matrix.

Examples
input
4 2
abcd
bcde
bcad
bcde
output
aaabcde
input
5 3
bwwwz
hrhdh
sepsp
sqfaf
ajbvw
output
aaaepfafw
input
7 6
ypnxnnp
pnxonpm
nxanpou
xnnpmud
nhtdudu
npmuduh
pmutsnz
output
aaaaaaadudsnz

思路:因為有k次修改機會,且要求字典序最小,那麼當然是儘量把前面的字元變為’a’,那麼我們可以求出序列中字首全為’a’的最長長度。

然後我們從這些字首的最後一個字元開始找出一條到達(n,n)(n,n)的字典序最小的路徑,我們把這些點走一步可能得到的字元找出來,並找到最小的那個字元加入到答案,然後再以這些最小的字元為起點,重複上述操作。

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e3+10;
char s[MAX][MAX];
int v[MAX][MAX];
int d[MAX][MAX];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
    memset(d,0,sizeof d);
    int ma=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i>1&&j>1)d[i][j]=min(d[i-1][j],d[i][j-1]);
            else if(i>1)d[i][j]=d[i-1][j];
            else if(j>1)d[i][j]=d[i][j-1];
            d[i][j]+=(s[i][j]!='a');
            if(d[i][j]<=m)ma=max(ma,i+j-1);//找出'a'的最長長度
        }
    }
    queue<int>p,q;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(d[i][j]<=m&&i+j-1==ma)//用這些點擴充套件求出答案
            {
                p.push(i);
                p.push(j);
            }
        }
    }
    string ans="";
    for(int i=1;i<=ma;i++)ans+='a';
    if(ma==0)
    {
        p.push(1);
        p.push(1);
        ans+=s[1][1];
        ma++;
    }
    for(int i=ma+1;i<=2*n-1;i++)
    {
        q=p;
        char nex='z';
        while(!p.empty())
        {
            int x=p.front();p.pop();
            int y=p.front();p.pop();
            if(x+1<=n)nex=min(nex,s[x+1][y]);//求出下一步得到的最小字元
            if(y+1<=n)nex=min(nex,s[x][y+1]);
        }
        ans+=nex;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            int y=q.front();q.pop();
            if(x+1<=n&&s[x+1][y]==nex&&v[x+1][y]==0)//以最小字元為起點繼續擴充套件
            {
                p.push(x+1);
                p.push(y);
                v[x+1][y]=1;
            }
            if(y+1<=n&&s[x][y+1]==nex&&v[x][y+1]==0)
            {
                p.push(x);
                p.push(y+1);
                v[x][y+1]=1;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}