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;
}