Codeforces Round #517 (Div. 2, based on Technocup 2019 Elimination Round 2) D. Minimum path(字典序)
阿新 • • 發佈:2018-11-12
https://codeforces.com/contest/1072/problem/D
題意
給你一個n*n充滿小寫字母的矩陣,你可以更改任意k個格子的字元,然後輸出字典序最小的從[1,1]到[n,n]的路徑(1<=n<=2000)
思路
我的
- 定義dp[i][j]為從[1,1]到[i,j]字串最小的字串,然後列舉所有i-1+j-1+1<=k的點,然後字串連線比較,代表更改前面i,j個字元
- 這種思路有兩個問題,如何處理出從[i,j]到[n,n]的最小字典序字串,第二假如i+j個字元中存在'a'的話那麼修改次數可以往後使用,這兩點都是這個思路沒有考慮到的
標解
- 我們如何得到字典序最小的字串?(逐位確定法)
- 固定了步數,我們就可以知道所有這個步數能到達的格子。然後我們列舉步數就等於在模擬走的過程,需要縱向比較所有當前步數所能到達的格子的字元大小,選取最小的繼續走,比他大的就不用繼續了,這樣就能保證得到的字串是最小的
- 怎麼處理最多隻能修改k個格子?
- 假如這個格子是'a',那麼這個格子就不用再修改
- 而對於一條還能修改的路徑來說,越多的a,意味著剩下還能修改的格子越多,
- 定義dp[i][j]代表到i,j最少a的路徑a的數量,
- dp[i][j]=min(dp[i-1][j],dp[i][j-1])+(s[i][j]!='a');
- 假如dp[i][j]<=k,那麼s[i][j]可以修改為a
#include<bits/stdc++.h> #define M 2005 using namespace std; int n,k,i,j,p,vi[M][M],f[M][M]; char s[M][M],mi; int main(){ cin>>n>>k; for(i=1;i<=n;i++)scanf("%s",s[i]+1); memset(f,1,sizeof(f)); f[0][1]=0; for(i=1;i<=n;i++)for(j=1;j<=n;j++){ f[i][j]=min(f[i-1][j],f[i][j-1])+(s[i][j]=='a'?0:1); if(f[i][j]<=k)s[i][j]='a'; } vi[1][1]=1; for(p=2;p<=2*n;p++){ mi='z'; for(i=1;i<=n;i++)if(p-i>=1&&p-i<=n&&vi[i][p-i])mi=min(mi,s[i][p-i]); putchar(mi); for(i=1;i<=n;i++)if(p-i>=1&&p-i<=n&&vi[i][p-i]&&s[i][p-i]==mi) vi[i+1][p-i]=vi[i][p-i+1]=1; } }