嘘~ 正在从服务器偷取页面 . . .

模拟赛题讲解[10]


模拟赛题讲解[10]

来自 xpp 2022-08-03 noi.ac #2723

题目描述

lzr给了xpp一个字符串 \(s\) 和一个字符串 \(t\) ,xpp想通过 \(s\) 构造出 \(t\) ,构造方式为xpp每次选择 \(s\) 的一个子序列,放到当前串的后面,xpp想知道他需要构造多少次才能构造出 \(t\) 呢?

输入格式

第一行一个数 \(T\) 表示数据组数。

对于每组数据第一行一个字符串 \(s\) ,第二行一个字符串 \(t\) ,含义见题目描述

输出格式

每组数据输出一行表示次数。如果不能输出 \(-1\)

输入1

3
aabce
ace
abacaba
aax
ty
yyt

输出1

1
-1
3

数据规模

对于 \(30\%\) 的数据, \(\texttt{字符串长度} \le 100\)

对于 \(100\%\) 的数据,\(\texttt{字符串长度} \le 10^5,~1\le T\le 10\)

题解

暴力的解法就是遍历 \(t\) ,然后维护一个指针 \(p\)\(s\) 上跳

仔细观察可以发现,如果 \(s=\tt{aaabbbbbbc}\)\(t=\tt{ac}\)

那么 \(p\) 就会慢悠悠的从 \(s\) 的第一个 \(\tt{a}\) 一直跑到最后的 \(\tt{c}\)

考虑维护一个 \(\text{nx}_{i,j}\) 表示 \(i\) 后面出现的第一个字符 \(j\) 的位置

这个东西的预处理还是很有趣的,我当时没想到怎么搞,然后就用二分草过了

for(int i=0; i<26; i++)
    for(int j=1; j<=n+1; j++)
        nx[i][j]=n+1;
for(int i=0; i<26; i++)
    for(int j=n; j>=1; j--)
        nx[i][j]=(s[j]=='a'+i)?j:nx[i][j+1];

时间复杂度 \(O(Qn)\)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e5+15)

int n,m,nx[26][N];
char s[N],t[N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int Q;cin >> Q;
    while(Q--)
    {
        cin >> (s+1) >> (t+1);
        n=strlen(s+1); m=strlen(t+1);
        for(int i=0; i<26; i++)
            for(int j=1; j<=n+1; j++)
                nx[i][j]=n+1;
        for(int i=0; i<26; i++)
            for(int j=n; j>=1; j--)
                nx[i][j]=(s[j]=='a'+i)?j:nx[i][j+1];
        int p=1,ans=1;
        for(int i=1; i<=m; i++)
        {
            int c=t[i]-'a';
            if(nx[c][1]==n+1) {ans=-1; break;}
            if(nx[c][p]==n+1) ++ans,p=1;
            p=nx[c][p]+1;
        }
        cout << ans << '\n';
    }
    return 0;
}

顺便附上我的考场代码(二分写法)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e5+15)

int n,m,p;
vector<int> ck[27];
string s,t;
void solve()
{
    cin >> s >> t; p=-1; int res=0;
    n=s.size(); m=t.size();
    for(int i=0; i<26; i++) ck[i].clear();
    for(int i=0; i<n; i++) ck[s[i]-'a'].push_back(i);
    for(int i=0; i<m; i++)
    {
        int c=t[i]-'a';
        if(ck[c].empty()) return cout << "-1\n",void(0);
        int nx=upper_bound(ck[c].begin(),ck[c].end(),p)-ck[c].begin();
        if(nx>=ck[c].size())
        {
            ++res;p=ck[c][0];
        }
        else p=ck[c][nx];
        // cout << p << '\n';
    }
    cout << res+1 << '\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int Q; cin >> Q;
    while(Q--) solve();
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录