【DP】【CF1099C】 Postcard

Description

给定一个长度为 \(n\) 的字符串,尽可能包含小写字母,字符 '?' 和字符 ‘*’。保证上面两种特殊字符若出现则一定出现在一个小写字母的后面一位。要求构造一个长度为 \(k\) 的新字符串,它和原串有如下关系:

按照原串的字母顺序向新串中填充,新串中含且仅含小写字母。

若原串的某小写字母后没有特殊字符,则这个字母在新串中必须保留

若原串的某小写字母后有字符 '?',则这个字母在新串中可以被保留,也可以被删除

若原串某小写字母后有字符 '*',则这个字母在新串中可以被保留,可以被删除,也可以被复读很多遍。

Input

第一行是一个长度为 \(n\) 的字符串,保证输入合法

第二行是一个整数 \(k\) 代表要求构造的新串长度

Output

输出一行一个长度为 \(k\) 的字符串,为构造出的串。

若不存在这样的串,输出“Impossible”(不含引号)

Hint

\(1~\leq~n,k~\leq~200\)

Solution

为啥泥萌一个贪心就过了啊qaq,为啥就我一人写了个DP还fst了啊qaq,我咋这么菜啊qaq

我们发现一个字母分别有三种情况:保留,保留/删除,保留/删除/复读。

于是我们处理一个新的字符串,只含给定串中的小写字母,另开数组记录该字母对应哪种情况。一下说的原串均指这个只含小写字母的新串,设原串长度为 \(len\)

于是问题就被转化为了按照原串一位一位的按照规则填能否填出一个长度为 \(k\) 的字符串。这显然是可以DP的。

其实正着DP大概是可做的,但是比赛的时候有点困就直接倒着DP的。我们设 \(f_{i,j}~=~true/false\) 为能否用原串 \([i,len]\) 位拼出新串的 \([j,k]\) 位。于是转移一共有三种情况:

1、只能保留:

\[f_{i,j}~=~f_{i + 1,j + 1}\]

2、保留或删除:

\[f_{i,j}~=~f_{i + 1,j + 1}~or~f_{i + 1,j}\]

3、保留,删除,复读:

\[f_{i,j}~=~f_{i + 1,j + 1}~or~f_{i + 1,j}~or~\bigvee_{h = j + 2}^{k + 1} f_{i + 1, h}~=~\bigvee_{h = j}^{k + 1} f_{i + 1, h}\]

其中 \(\bigvee_{i = a}^{b} s(i)\) 为若 \(\exists~i_0~\in~[a,b],~s.t.~~s(i_0)~=~true\) 则返回 \(true\),否则返回 \(false\)

初始化为 \(f_{len + 1, k + 1} = true\)

在转移时记录一下转移方向就可以输出方案了。

Code

#include <cstdio>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
#define rg register
#define ci const int
#define cl const long long

typedef long long ll;

namespace IPT {
    const int L = 1000000;
    char buf[L], *front=buf, *end=buf;
    char GetChar() {
        if (front == end) {
            end = buf + fread(front = buf, 1, L, stdin);
            if (front == end) return -1;
        }
        return *(front++);
    }
}

template <typename T>
inline void qr(T &x) {
    rg char ch = IPT::GetChar(), lst = ' ';
    while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    if (lst == '-') x = -x;
}

template <typename T>
inline void ReadDb(T &x) {
    rg char ch = IPT::GetChar(), lst = ' ';
    while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
    while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
    if (ch == '.') {
        ch = IPT::GetChar();
        double base = 1;
        while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
    }
    if (lst == '-') x = -x;
}

namespace OPT {
    char buf[120];
}

template <typename T>
inline void qw(T x, const char aft, const bool pt) {
    if (x < 0) {x = -x, putchar('-');}
    rg int top=0;
    do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
    while (top) putchar(OPT::buf[top--]);
    if (pt) putchar(aft);
}

const int maxn = 210;

int Len, k, len;
char MU[maxn], CU[maxn];
int pre[maxn][maxn], vc[maxn];
bool frog[maxn][maxn];

void print(ci, ci);

int main() {
    freopen("1.in", "r", stdin);
    do MU[++Len] = IPT::GetChar(); while (((MU[Len] >= 'a') && (MU[Len] <= 'z')) || (MU[Len] == '?') || (MU[Len] == '*'));
    for (rg int i = 1; i <= Len; ++i) if ((MU[i] >= 'a') && (MU[i] <= 'z')) {
        CU[++len] = MU[i];
        switch (MU[i + 1]) {
            case '?': {
                vc[len] = 1;
                break;
            }
            case '*': {
                vc[len] = 2;
                break;
            }
        }
    }
    qr(k);
    frog[len + 1][k + 1] = true;
    rg int dk = k + 1;
    for (rg int i = len; i; --i) {
        rg int di = i + 1;
        for (rg int j = 1; j <= dk; ++j) {
            switch(vc[i]) {
                case 0: {
                    if (frog[di][j + 1]) {
                        frog[i][j] = true;
                        pre[i][j] = j + 1;
                    }
                    break;
                }
                case 1: {
                    if (frog[di][j + 1]) {
                        frog[i][j] = true;
                        pre[i][j] = j + 1;
                    } else if (frog[di][j]) {
                        frog[i][j] = true;
                        pre[i][j] = j;
                    }
                    break;
                }
                case 2: {
                    for (rg int h = j; h <= dk; ++h) if (frog[di][h]) {
                        frog[i][j] = true;
                        pre[i][j] = h;
                        break;
                    }
                    break;
                }
            }
        }
    }
    if (frog[1][1]) print(1, 1);
    else puts("Impossible");
    return 0;
}

void print(ci cur, ci v) {
    if (cur > len) return;
    for (rg int i = v; i < pre[cur][v]; ++i) putchar(CU[cur]);
    print(cur + 1, pre[cur][v]);
}

转载于:https://www.cnblogs.com/yifusuyi/p/10231438.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值