Codeforces 1295C - Obtain The String

题目大意:

给定两个字符串s和t,你有一个空字符串z

每次可以取s的任意一个子序列加到z后面

问至少要取多少次才能让z等价于t

解题思路:

vector存s中26个字母的位置

然后t字符串从前往后一个个查找

用变量p记录查到上一个字符时在字符串s中的位置(初始化为-1)

如果在t内碰到一个字符,没有在s中出现过,输出-1结束当次程序

否则,看当前的p是否大于等于这个字符在s中出现的最后一个位置

如果是,说明这一次子序列已经不能往后面取了,说明得另起一次从头取子序列

ans++,让p等于当前字符在s中出现的第一个位置

如果不是二分找大于p的第一个这个字符的位置,让p等于这个位置即可

注意,ans初始化为1,vector要清空……

思路用到了一点点贪心,就是每次都是取上一次的位置后出现的第一个指定字符的位置

反正正常模拟肯定超时要二分优化,嗯!

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 string s,t;
 4 vector<int> v[26];
 5 int siz[26];
 6 inline int gid(char s){
 7     return s-'a';
 8 }
 9 void solve(){
10     cin>>s>>t;
11     memset(siz,0,sizeof siz);
12     int lens=s.size(),lent=t.size(),i,j,d,p=-1,pd,ans=1;
13     for(i=0;i<26;i++)
14         v[i].clear();
15     for(i=0;i<lens;i++){
16         d=gid(s[i]);
17         v[d].emplace_back(i);
18         siz[d]++;
19     }
20     for(i=0;i<lent;i++){
21         d=gid(t[i]);
22         if(siz[d]==0){//这个字符没有出现过
23             cout<<"-1\n";
24             return;
25         }
26         if(p>=v[d][siz[d]-1]){//如果已经没法在剩下的位置中取这个字符了,得另起一次从头开始取子序列
27             ans++;
28             p=v[d][0];
29         }
30         else{//否则,二分找大于p的第一个这个字符的位置
31             pd=upper_bound(v[d].begin(),v[d].end(),p)-v[d].begin();
32             p=v[d][pd];
33         }
34     }
35     cout<<ans<<'\n';
36 }
37 int main(){
38     ios::sync_with_stdio(0);
39     cin.tie(0);cout.tie(0);
40     int T;cin>>T;while(T--)
41         solve();
42     
43     return 0;
44 }

猜你喜欢

转载自www.cnblogs.com/stelayuri/p/12241989.html