chenfy27的刷题记录

导航

abc324E 合并两字符串后能得到某个子序列的方案数

给定n个字符串s[n]和字符串t,从中任选一对下标(i,j),要求i<=j,让s[i]与s[j]连起来得到一个新的串,要求由新串删除0个或多个字符可以得到t,问存在多少对满足条件的下标对?
1<=n<=5E5; 1<=len(s[i]),len(t)<=5E5

分析:假设由字符串x能得到t的前缀长度为a,字符串y能得到t的后缀长度为b,如果a+b>=len(t),那么由x+y一定能得到子序列t。计数那里可以开cnt数组统计,然后求前缀和,这里偷懒直接套平衡树模板。

#include <bits/stdc++.h>
using i64 = long long;

// Treap模板...

int getpre(const string &s, const string &t) {
    int k = 0;
    int ns = s.size(), nt = t.size();
    for (int i = 0, j = 0; i < ns && j < nt; i++) {
        if (s[i] == t[j]) {
            j += 1;
            k += 1;
        }
    }
    return k;
}
int getsuf(const string &s, const string &t) {
    int k = 0;
    int ns = s.size(), nt = t.size();
    for (int i = ns-1, j = nt - 1; i >= 0 && j >= 0; i--) {
        if (s[i] == t[j]) {
            j -= 1;
            k += 1;
        }
    }
    return k;
}

const int N = 500005;
int n;
std::string T, S[N];
void solve() {
    std::cin >> n >> T;
    Treap<int> tp;
    for (int i = 1; i <= n; i++) {
        std::cin >> S[i];
        int pre = getpre(S[i], T);
        tp.insert(pre);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        int suf = getsuf(S[i], T);
        ans += tp.gecnt(T.size() - suf);
    }
    std::cout << ans << "\n";
}

int main() {
    std::cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}

posted on 2024-03-17 18:17  chenfy27  阅读(14)  评论(0)    收藏  举报