• Color Length UVALive


    题文:见网页:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3852,(紫书p276)

    题解:

    这个题目统计答案,或者说状态的转移十分巧妙,我们想如果设dp[i][j]表示一号串到了第i位,二号串到了第j位的最小话费,显然还要记一下最开始放入这个字母的位置,十分不好写对不对,并且也状压不下。

    那么我们可以考虑,对于一个状态dp[i][j],我们不最后来算他是多少,我们可以一边加,一边判断,看前面有那些字母已经出现了,并且后面还有这个字母,那么显然对于每个这种字母,都要有1的花费,所以,这个题目就变成了如何维护当前满足上述定义的字母的个数,这个我们主要分类讨论一下就可以了,具体实现看代码吧。

    代码:(其实可以不用滚动数组)

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<cstring>
    #include<stdlib.h>
    #define ll long long
    const int MAXN=5010;
    const int inf=1<<30;
    using namespace std;
    int dp[2][MAXN],c[2][MAXN];
    int op1[27],ed1[27],op2[27],ed2[27];
    int n,m;
    char x[MAXN],y[MAXN];
    int main(){
        int t;scanf("%d",&t);
        while(t--){
            memset(dp,0,sizeof(dp));
            memset(c,0,sizeof(c));
            scanf("%s%s",x+1,y+1);
            int n=strlen(x+1),m=strlen(y+1);
            for(int i=1;i<=n;i++) x[i]-='A';
            for(int i=1;i<=m;i++) y[i]-='A';
            memset(op1,127,sizeof(op1));
            memset(op2,127,sizeof(op2));
            memset(ed1,0,sizeof(ed1));
            memset(ed2,0,sizeof(ed2));
            for(int i=1;i<=n;i++){
                op1[x[i]]=min(op1[x[i]],i);
                ed1[x[i]]=i;
            }
            for(int i=1;i<=m;i++){
                op2[y[i]]=min(op2[y[i]],i);
                ed2[y[i]]=i;
            }
            int now=0,last=1;dp[0][0]=0;
            for(int i=0;i<=n;i++){
                now^=1,last^=1;
                memset(dp[now],0,sizeof(now));
                memset(c[now],0,sizeof(now));
                for(int j=0;j<=m;j++){
                    if(!i&&!j) continue;
                    int v1=inf,v2=inf;
                    if(j) v1=dp[now][j-1]+c[now][j-1];
                    if(i) v2=dp[last][j]+c[last][j];
                    dp[now][j]=min(v1,v2);
                    if(i){
                        c[now][j]=c[last][j];
                        if(op1[x[i]]==i&&op2[x[i]]>j) c[now][j]++;
                        if(ed1[x[i]]==i&&ed2[x[i]]<=j) c[now][j]--;
                    }
                    else if(j){
                        c[now][j]=c[now][j-1];
                        if(op2[y[j]]==j&&op1[y[j]]>i) c[now][j]++;
                        if(ed2[y[j]]==j&&ed1[y[j]]<=i) c[now][j]--;
                    }
                }
            }
            printf("%d
    ",dp[now][m]);
        }
    }
  • 相关阅读:
    PHP 方法整合类 -- 1.根据概率产生随机数 --2.判断手机号归属地及运营商 --3.过滤emoji表情
    PHP 多图下载并打包压缩方法
    PHP 导出excel 精简版
    PHP获取首字母相关方法
    no input file specified 解决办法
    百度地图相关
    经纬度相关方法
    阿里云SSL证书部署至宝塔
    微信入口、生成菜单,公众号授权获取用户信息(unionid)
    超级好用超级简单的支付类库
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7309200.html
Copyright © 2020-2023  润新知