sgu 237Galaxy X: Episode I

来源:互联网 发布:视频合并软件绿色版 编辑:程序博客网 时间:2024/05/17 03:49

题意:

给你一个包含’‘、’?’、’!’、’a’~’z’的字符串,其中’‘可以被任意字符串替换(包括空串),’?’必须恰好被一个字符替换,’!’必须恰好被三个字符替换。要求按规则替换后原串要变成一个回文串且长度要求最小;若长度相同则要求字典序最小。

tip:

第一次做的时候按照dp[i][j]表示前I个和后j个能否匹配,匹配的最小长度是多少。松弛:

void rel(int i,int j,int i2,int j2,int lenth){    if(dp[i2][j2].first == false){        return ;    }    dp[i][j].first = true;    if(dp[i2][j2].second + lenth  < dp[i][j].second){        dp[i][j].second = dp[i2][j2].second + lenth;   }}

当s[i]或者s[j]是的时候,要枚举一个k,表示右边k个和左边※之前的匹配。。。长度要减去j到k之前是的。因为后面的*是空字符才是最优,不然现在左边这个星还要匹配他

 for(int i = 1 ; i <= n ; i++){        for(int j = 1 ; j <= n ; j++){            int l = i-1, r = n-j;            if(is_low(p[l]) && is_low(p[r])){                if(p[l] != p[r]){                    dp[i][j].first = false;                }                else{                    rel(i,j,i-1,j-1,1);                }            }            else if( p[r] == '?' ||  p[l] == '?'){                rel(i,j,i-1,j-1,1);            }            else if(p[l] == '*' ){                for(int k = 0; k <= j ; k++){                    r2 = n-k;                    rel(i,j,i-1,k,r2-r-(cnt[r2-1]-cnt[r-1]) );                }            }            else if(p[r] == '*' ){                for(int k = 0 ; k <= i ; k++){                    l2 = k-1;                    rel(i,j,k,j-1,l-l2-(cnt[l]-cnt[l2]));                }            }        }    }

初始化开头结尾是*的时候

dp[0][0] = make_pair(true,0);if(p[n-1] == '*')   dp[1][0] = make_pair(true,0);if(p[0] == '*') dp[0][1] = make_pair(true,0);

tip2:

当然了。。这样并不能ac,因为这样字典序并不是最小的,只能保证长度是最小的。因为如果倒着去输出答案就会优先让中间那一段的字典序最优。所以换了一种dp,dp[I][j]表示从j到j+i-1匹配上的字符串是什么样的,也就是说i是长度,这样写起来更方便一些.类似区间dp,比当前长度小的,从任意字符开始匹配上的最小字符串都求好了,

下面用k表示I+j-1 当前区间是【j,k】

如果s[j] s[k]都是星,可以两个都放空字符串
dp[I][j] = dp[I-2][j+1]
右边的星为空:
dp[I][j] = dp[I-1][j]
左边为空:
dp[I][j] = dp[I-1][j+1]

如果s[j]是星,s[k]不是。
左边这个星为空:
dp[I][j] = dp[I-1][j+1],
不为空:
dp[I][j] = s[k]+dp[I-1][j]+s[k];
(这个星可能之前对I-1长度时候已经填了东西)

s[k]为星同理。
都不是星判断一下s[j] s[k]是否可以一样(?的存在)
但是这个sgu对内存要求挺高的。。然后我们发现,每次的dp之和上两次的长度,也就是I-1 I-2有关系,那么可以三维滚动。。。p是i-2,q是i-1,now是现在。。

p = (p+1)%3;q = (q+1)%3;now = (now+1)%3;

松弛的时候,比较字符串长度,长度相同,比较字典序

void rel(const string s,int now, int i){    if((int)dp[now][i] .size() > (int)s.size() || ((int)dp[now][i] .size()==(int)s.size()&&dp[now][i]  > s))        dp[now][i]  = s;}

全部代码:

#include <cstdio>#include <string>#include <cstring>#include <iostream>using namespace std;typedef pair<bool,string>pii;const int maxn = 260;const int maxm = maxn*3;string none = "";char a[maxn], s[maxm],tmp;string dp[3][maxm];int p ,q,now,n ,len;void init(){    scanf("%s", a);    len = strlen(a);    for(int i = 0 ; i < 400 ; i++)none += "NO";    for(int i = 0; i < len; i++){        if(a[i] == '!') s[++n] = '?', s[++n] = '?', s[++n] = '?';        else s[++n] = a[i];    }    for(int i = 1; i <= n; i++){        if(s[i] == '*') { dp[1][i] = "";}        else{            dp[1][i] = (s[i]=='?'?'a':s[i]);        }    }}void rel(const string s,int now, int i){    if((int)dp[now][i] .size() > (int)s.size() || ((int)dp[now][i] .size()==(int)s.size()&&dp[now][i]  > s))        dp[now][i]  = s;}void sov(){    p = 0,q = 1, now = 2;    for(int i = 2; i <= n; i++){        for(int j = 1; j <= n; j++){            int k = i+j-1;            if(k > n)   break;            if(s[j] == '*' && s[k] == '*'){                dp[now][j]  = dp[p][j+1] ;//都是空                //cout << p <<"  "<<j+1 <<"  "<<dp[p][j+1] <<endl;                rel(dp[q][j] ,now, j);//右空                rel(dp[q][j+1] ,now, j);//左空            }            else if(s[j] == '*' && s[k] != '*'){                dp[now][j]  = dp[q][j+1] ;                tmp = s[k];                if(s[k] == '?') tmp = 'a';                rel(tmp+dp[q][j] +tmp, now,j);            }            else if(s[k] == '*'){                dp[now][j]  = dp[q][j] ;                tmp = s[j];                if(s[j] == '?') tmp = 'a';                //cout <<"j = "<<j <<"  k " <<k<<dp[q][j]  <<endl;                rel(tmp+dp[q][j+1] +tmp,now, j);            }            else{                if(s[j] == '?'){                    tmp = s[k];                    if(s[k] == '?') tmp = 'a';                    dp[now][j]  = tmp+dp[p][j+1] +tmp;                }                else if(s[k] == '?' || s[j] == s[k]) dp[now][j]  = s[j]+dp[p][j+1] +s[j];                else dp[now][j] = none;            }        }        p = (p+1)%3;q = (q+1)%3;now = (now+1)%3;    }}bool check(const string s){    for(int i = 0, j = s.size()-1; i < j; i++, j--)        if(s[i] != s[j]) return false;    return true;}void print(){    now = (now+3-1)%3;    if(check(dp[now][1] ) ){        cout << "YES" << endl;        cout << dp[now][1]  << endl;    }    else cout << "NO" << endl;}int main(){    init();    sov();    print();    return 0;}