【动态规划】[UVa1625]Color Length

分析一下发现如果每一次放进去一个新,它就会对所有覆盖这个点的所有颜色的L加1那么另 add(i,j) 为第一个放到i第二个放到j放完之后这种状态有多少组交叉那么有

int add(int x, int y) {
    int cnt = 0;
    for(int i=0;i<26;i++){
        if(pos[i][1] <= x && pos2[i][1] <= y) continue;
        if(pos[i][0] > x && pos2[i][0] > y) continue;
        if(pos[i][0] > x && pos2[i][0] == -1) continue;
        if(pos2[i][0] > y && pos[i][0] == -1) continue;
        cnt++;
    }
    return cnt;
}

之前可以先预处理一下每一种颜色在每一段中的起始位置和结束位置

void Init(){
    memset(pos, -1, sizeof pos);
    memset(pos2, -1, sizeof pos2);
    int len = strlen(s1+1);
    for(int i=1;i<=len;i++)
        pos[s1[i]-'A'][1] = i;
    for(int i=len;i>=1;i--)
        pos[s1[i]-'A'][0] = i;
    len = strlen(s2+1);
    for(int i=1;i<=len;i++)
        pos2[s2[i]-'A'][1] = i;
    for(int i=len;i>=1;i--)
        pos2[s2[i]-'A'][0] = i;
}

然后很容易发现 f(i,j)=min{f(i1,j),f(i,j1)}+add(i,j) 记得要用滚动数组,不然直接二位数组要爆

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100000;
int pos[26][2], pos2[26][2];
char s1[MAXN+10], s2[MAXN+10];
void Init(){
    memset(pos, -1, sizeof pos);
    memset(pos2, -1, sizeof pos2);
    int len = strlen(s1+1);
    for(int i=1;i<=len;i++)
        pos[s1[i]-'A'][1] = i;
    for(int i=len;i>=1;i--)
        pos[s1[i]-'A'][0] = i;
    len = strlen(s2+1);
    for(int i=1;i<=len;i++)
        pos2[s2[i]-'A'][1] = i;
    for(int i=len;i>=1;i--)
        pos2[s2[i]-'A'][0] = i;
}
int add(int x, int y) {
    int cnt = 0;
    for(int i=0;i<26;i++){
        if(pos[i][1] <= x && pos2[i][1] <= y) continue;
        if(pos[i][0] > x && pos2[i][0] > y) continue;
        if(pos[i][0] > x && pos2[i][0] == -1) continue;
        if(pos2[i][0] > y && pos[i][0] == -1) continue;
        cnt++;
    }
    return cnt;
}
const int INF = 999999999;
int dp[2][MAXN+5];
int solve(){
    memset(dp, 0, sizeof dp);
    int now = 0, len1 = strlen(s1+1), len2 = strlen(s2+1);
    for(int i=1;i<=len2;i++) dp[now][i] = INF;
    for(int i=0;i<=len1;i++){
        now ^= 1;
        for(int j=0;j<=len2;j++)
            dp[now][j] = min(((j-1)>=0?dp[now][j-1]:INF), dp[now^1][j]) + add(i, j);
    }
    return dp[now][len2];
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%s%s", s1+1, s2+1);
        Init();
        printf("%d\n", solve());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值