1. 程式人生 > >【Codeforces Round #517 (Div. 2, based on Technocup 2019 Elimination Round 2) D. Minimum path】dp+滾動陣列

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