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;
}
浙公网安备 33010602011771号