• 【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~igvee_{h = j + 2}^{k + 1} f_{i + 1, h}~=~igvee_{h = j}^{k + 1} f_{i + 1, h} ]

    其中 (igvee_{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]);
    }
    
  • 相关阅读:
    自己的文件管理软件,想怎样分类管理就怎样分类
    给博客园发展支点招
    看看自己存在哪些的个人知识管理问题和烦恼呢?
    2008年个人知识管理软件测评[草稿]
    獲取某天是星期幾
    創建鏈接服務器
    在.NET中调用Oracle9i存储过程经验总结
    C#转换成VB.net或vb.net转换成C#
    話說我們家姚明
    解决winxp搜索不到文件的问题!
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10231438.html
Copyright © 2020-2023  润新知