zoukankan      html  css  js  c++  java
  • 【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]);
    }
    
  • 相关阅读:
    oracle 监听静态注册举例解析
    oracle监听动态注册与静态注册
    oracle startup mount nomount 区别
    RAC的时间同步问题
    RAC环境TNS-12541报错处理
    Oracle参数修改是否需要重启等
    面试提纲
    Dubbo是什么
    为什么要用dubbo,dubbo和zookeeper关系
    Java的参数传递是「按值传递」还是「按引用传递」?
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10231438.html
Copyright © 2011-2022 走看看