E - Unpleasant Strings
题目链接:https://codeforces.com/contest/2104/problem/E
题意:
题目中出现的字符串字符都是前k个字符
给定一个字符串s,和若干个字符串t。
对于每一个字符串t,求使得它不再是s的子序列所需要增加的最小字符数量
思路:
由于需要快速查找每个字符串t最后一个子符 在字符串s中作为子序列的位置
我们需要构建next数组,即每一个位置 后面第一次出现某个字符的位置
从后往前遍历
next[i]=next[i],next[i][s[i+1]-'a']=i+1
(其实跟后缀和差不多)
确定了每个t在s的最后一个位置后,需要考虑如何进行最小的转移
因此需要通过一维dp转移状态
记dp[i]:为 结尾为字符s[i]的字符串t所需要增加字符“跳出”字符串s的最小数量
再从后往前看
那么O(nk)时间,可以转移dp[i]=min(dp[i],dp[next[i][j]]+1)
需要在所有状态下找到最优解
需要花费1个字符的代价转移到另外一个状态
另外dp[n]=1,dp[n+1]=0,然后要从位置0开始跳转
void solve(){
int n,k;cin>>n>>k;
string s;cin>>s;
s=" "+s;
vector<vector<int>>next(n+2,vector<int>(k+1,n+1));
for(int i=n-1;i>=0;i--){
next[i]=next[i+1];
next[i][s[i+1]-'a']=i+1;
}
vector<int>dp(n+2,n);
dp[n+1]=0;
dp[n]=1;
for(int i=n-1;i>=0;i--){
for(int j=0;j<k;j++){
dp[i]=min(dp[i],dp[next[i][j]]+1);
}
}
// rep(i,1,n)debug(dp[i]);
int q;cin>>q;
while(q--){
string t;cin>>t;
int m=t.size();
t=" "+t;
int cur=0;
for(int i=1;i<=m;i++){
if(cur>n)break;
cur=next[cur][t[i]-'a'];
}
cout<<dp[cur]<<endl;
}
}

浙公网安备 33010602011771号