• Codeforces Round #517 (Div. 2, based on Technocup 2019 Elimination Round 2) D. Minimum path(字典序)


    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;
        }
    }
    
    
    
    
  • 相关阅读:
    软件工程第十四周学习进度条
    软件工程第十五周学习进度条
    课堂练习-买书价格最低
    找水王2
    Struts结合马士兵视频的学习经验
    Spring结合马士兵视频的学习经验
    浅谈 《大型网站技术架构》 五六七章
    以《淘宝网》为例,描绘质量属性的六个常见属性场景
    浅谈架构漫谈
    软件架构设计师工作流程
  • 原文地址:https://www.cnblogs.com/VIrtu0s0/p/9946230.html
Copyright © 2020-2023  润新知