[UVa-437] Color Length

Description

给出两个字符串$a$,$b$,将他们穿插起来(相对位置不变),要求最小化$\sum L(c)$,其中$L(c)$的定义时在穿插完的字符串中字符$c$的最大位置与最小位置的差。

$n \leq 5000$。

Solution

问题的转化

这样的问题并不好用子问题来做,考虑最小化贡献。

贡献是可以$DP$的。令$dp_{i,j}$表示将$a$的前$i$个与$b$的前$j$个合并后对答案的最优贡献。维护每个字母第一次出现的状态和最后一次出现的状态转移即可。

/*By DennyQi 2019*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 10010;
const int MAXM = 20010;
const int INF = 0x3f3f3f3f;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int T,dp[5010],cnt[5010],lsta[30],lstb[30],fsta[30],fstb[30],la,lb;
char a[5010],b[5010];
inline void Init_cnt(){
    memset(lsta,0,sizeof(lsta));
    memset(lstb,0,sizeof(lstb));
    memset(fsta,0x3f,sizeof(fsta));
    memset(fstb,0x3f,sizeof(fstb));
    for(int i = 1; i <= la; ++i){
        lsta[a[i]-'A'] = max(lsta[a[i]-'A'],i);
        fsta[a[i]-'A'] = min(fsta[a[i]-'A'],i);
    }
    for(int i = 1; i <= lb; ++i){
        lstb[b[i]-'A'] = max(lstb[b[i]-'A'],i);
        fstb[b[i]-'A'] = min(fstb[b[i]-'A'],i);
    }
}
inline void DP(){
    memset(dp,INF,sizeof(dp));
    memset(cnt,0,sizeof(cnt));
    char cur;
    dp[0] = 0;
    for(int i = 0; i <= la; ++i){
        for(int j = 0; j <= lb; ++j){
            if(i==0 && j==0) continue;
            if(i == 0){    
                cnt[j] = cnt[j-1];
                cur = b[j]-'A';
                if(j == fstb[cur]) ++cnt[j];
                if(j == lstb[cur] && lsta[cur] == 0) --cnt[j];
            }
            else{
                cur = a[i]-'A';
                if(j >= lstb[cur] && i >= lsta[cur]) --cnt[j];
                if(j < fstb[cur] && i == fsta[cur]) ++cnt[j];
            }
            dp[j] = min((j==0)?INF:dp[j-1], (i==0)?INF:dp[j])+cnt[j];
        }
    }
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%s%s",a+1,b+1);
        la = strlen(a+1), lb = strlen(b+1);
        Init_cnt();
        DP();
        printf("%d\n",dp[lb]);
    }
    return 0;
}
posted @ 2019-02-17 09:23  DennyQi  阅读(236)  评论(1编辑  收藏  举报