典型的代价优先计算dp

难点就在计算代价上。。。

很巧的是,每次合并,代价就是i,j组成的序列中,开始了但是没有结束的字母种类数

【1】普通dp tle不知道多少个点

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
inline int read()
{
    int x=0;char c=getchar();
    while(c<'0' || c>'9' ) c=getchar();
    while(c>='0'&&c<='9' ) x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x;
}
inline void wr(int x)
{
    if(x>=10) wr(x/10);
    putchar(x%10+'0');
}

int n;
const int N=5e3+3;
char a[N],b[N];
int la,lb,da[N],db[N];
int sum[26],cnt[2][N][26];

int w[N][N];
int f[N][N];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        la=lb=0;
        //pre0
        scanf("%s%s",a+1,b+1);
        while(a[++la])
            da[la]=a[la]-'A',sum[da[la]]++,cnt[0][la][da[la]]++;
        while(b[++lb])
            db[lb]=b[lb]-'A',sum[db[lb]]++,cnt[1][lb][db[lb]]++;
        la--,lb--;
        for(int i=1;i<=la;i++)
        {
            int res=0;
            for(int j=0;j<26;j++)
            {
                cnt[0][i][j]+=cnt[0][i-1][j];
                if(cnt[0][i][j] && cnt[0][i][j]!=sum[j] )
                    res++;
            }
            w[i][0]=res;
        }
        for(int i=1;i<=lb;i++)
        {
            int res=0;
            for(int j=0;j<26;j++)
            {
                cnt[1][i][j]+=cnt[1][i-1][j];
                if(cnt[1][i][j] && cnt[1][i][j]!=sum[j] )
                    res++;
            }
            w[0][i]=res;
        }
        //pre1
        for(int i=1;i<=la;i++)
            for(int j=1;j<=lb;j++)
            {
                w[i][j]=w[i][j-1];
                if(cnt[0][i][db[j]] + cnt[1][j][db[j]] ==sum[db[j]] )
                    w[i][j]--;
                if(!cnt[1][j-1][db[j]] && !cnt[0][i][db[j]] )
                    w[i][j]++;
            }
        //work
        memset(f,0x3f,sizeof(f));
        f[0][0]=0;
        for(int j=1;j<=lb;j++) f[0][j]=f[0][j-1]+w[0][j-1];
        for(int i=1;i<=la;i++)
        {
            f[i][0]=f[i-1][0]+w[i-1][0];
            for(int j=1;j<=lb;j++)
                f[i][j]=min(f[i][j-1]+w[i][j-1],f[i-1][j]+w[i-1][j] ),
                printf("%d ",f[i][j]);
            printf("\n");
        }
        wr(f[la][lb]),putchar('\n');
    }

    return 0;
}
View Code

【2】滚动数组优化 时间和空间

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
inline int read()
{
    int x=0;char c=getchar();
    while(c<'0' || c>'9' ) c=getchar();
    while(c>='0'&&c<='9' ) x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x;
}
inline void wr(int x)
{
    if(x>=10) wr(x/10);
    putchar(x%10+'0');
}

int n;
const int N=5e3+3;
char a[N],b[N];
int la,lb,da[N],db[N];
int sum[26],cnt[2][N][26];

int w[2][N];
int f[2][N];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        memset(f,0x3f,sizeof(f));
        la=lb=0;
        //pre0
        scanf("%s%s",a+1,b+1);
        while(a[++la])
            da[la]=a[la]-'A',sum[da[la]]++,cnt[0][la][da[la]]++;
        while(b[++lb])
            db[lb]=b[lb]-'A',sum[db[lb]]++,cnt[1][lb][db[lb]]++;
        la--,lb--;
        for(int i=1;i<=la;i++)
            for(int j=0;j<26;j++) cnt[0][i][j]+=cnt[0][i-1][j];
        for(int i=1;i<=lb;i++)
            for(int j=0;j<26;j++) cnt[1][i][j]+=cnt[1][i-1][j];

        f[0][0]=w[0][0]=0;
        for(int i=1;i<=lb;i++)
        {
            w[0][i]=w[0][i-1];
            if(!cnt[1][i-1][db[i]] ) w[0][i]++;
            if( cnt[1][i][db[i]] == sum[db[i]] ) w[0][i]--;
            f[0][i]=f[0][i-1]+w[0][i-1];
        }
        for(int i=1;i<=la;i++)
        {
            int nw=i&1,pre=nw^1;
            //pre1
            w[nw][0]=w[pre][0];//对应w[i][0] 
            if(cnt[0][i][da[i]] == sum[da[i]]) w[nw][0]--;
            if(cnt[0][i-1][da[i]] == 0 ) w[nw][0]++;
            for(int j=1;j<=lb;j++)//对应w[i][j] 
            {
                w[nw][j]=w[nw][j-1];
                if(cnt[0][i][db[j]] + cnt[1][j][db[j]] ==sum[db[j]] ) w[nw][j]--;
                if(!cnt[1][j-1][db[j]] && !cnt[0][i][db[j]] ) w[nw][j]++;
            }
            //work
            f[nw][0]=f[pre][0]+w[pre][0];
            for(int j=1;j<=lb;j++)
                f[nw][j]=min(f[pre][j]+w[pre][j],f[nw][j-1]+w[nw][j-1]);
        }
        wr(f[la&1][lb]),putchar('\n');
    }

    return 0;
}
View Code
01-01 14:47