1368. 最长前缀

状态表示:

\(f(i)\):前缀\(s[1 \sim i]\)能否由子串集合中的元素表示。

\(f(i)\)只有\(true\)\(false\)两种取值。

状态转移:

对每个子串\(p[i]\),若\(s[i]\)大小为\(p[i]\)长度的后缀与\(p[i]\)匹配,则有如下转移:

\[f(i) \ |= f(i-p[i].size()) \]

const int N=2e5+10;
bool f[N];
string a[210];
string s;
int n;

int main()
{
    while(cin>>s, s[0] != '.')
        a[n++]=s;

    s.clear();
    string line;
    while(cin>>line) s += line;

    f[0]=true;
    int res=0;
    for(int i=1;i<=s.size();i++)
        for(int j=0;j<n;j++)
        {
            int t=a[j].size();
            if(i >= t && s.substr(i-t,t) == a[j])
                f[i] |= f[i-t];
            if(f[i]) res=i;
        }
    
    cout<<res<<endl;
    //system("pause");
    return 0;
}

判断某一后缀是否由子串集合中的元素组成,不必枚举所有子串,可以借助哈希表优化。由于子串的长度不超过\(10\),所以按长度从小到大枚举后缀,判断该后缀是否在哈希表(子串集合)中。

const int N=2e5+10;
bool f[N];
unordered_set<string> S;
string s;
int n;

int main()
{
    while(cin>>s, s[0] != '.')
        S.insert(s);

    s.clear();
    string line;
    while(cin>>line) s += line;

    f[0]=true;
    int res=0;
    for(int i=1;i<=s.size();i++)
        for(int j=1;j<=min(i,10);j++)
        {
            string t=s.substr(i-j,j);
            if(S.count(t))
                f[i] |= f[i-j];
            if(f[i]) res=i;
        }

    cout<<res<<endl;

    //system("pause");
    return 0;
}
posted @ 2021-06-04 15:28  Dazzling!  阅读(34)  评论(0编辑  收藏  举报