CF1902E Collapsing Strings
字典树板题,但是脑子没转过来导致写了很久。
由于字符串的总长度可以接受,所以考虑先建树,然后一个串一串跑,因为字典树单词查询的复杂度是 O(字符串长度),所以复杂度是可以接受的。
由于涉及到翻转,一开始一直以为要建两棵树,结果 MLE 了,看了眼题解之后大彻悟建一棵就够了,把 \(s_i\) 反转一下来查询就可以了。
反思一下,如果对着 \(\sum_{i = 1}^{n}\sum_{j = 1}^{n}C(s_i, s_j)\) 这个式子分析的话,至少可以快40min,自己考虑复杂了,贡献的构成没有想的很清楚。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int N = 1e6 + 1000;
int ch[N][26], f[N];
int cnt = 0;
string s[N];
void insert(string t){
int len = t.size(), u = 0;
F(i, 0, len - 1){
int v = t[i] - 'a';
if(!ch[u][v]) ch[u][v] = ++ cnt;
u = ch[u][v];
}
++ f[u];
}
void dfs(int u){
F(i, 0, 25){
if(ch[u][i]){
int v = ch[u][i];
dfs(v);
f[u] += f[v];
}
}
}
ll ask(string t){
int len = t.size(), u = 0;
ll sum = 0;
F(i, 0, len - 1){
int v = t[i] - 'a';
if(!ch[u][v]) break;
u = ch[u][v];
sum += f[u];
// printf("%c\tf = %d\n", t[i], f[u]);
}
return sum;
}
int n;
void Main(){
ll ans = 0, ss = 0;
cin >> n;
F(i, 1, n){
cin >> s[i];
int l = s[i].size();
ss += l;
insert(s[i]);
}
dfs(0);
// F(i, 1, t.cnt){
// printf("t.f[%d] = %d\t", i, t.f[i]);
// }
// printf("\n");
F(i, 1, n){
// ll tmp1 = ask(s[i]);
reverse(s[i].begin(), s[i].end());
ll tmp = ask(s[i]);
// printf("i = %d\t tmp = %lld\n", i, tmp);
ans += tmp;
}
// printf("ss = %lld, ans = %lld\n", ss, ans);
cout << ss * n * 2 - ans * 2 << '\n';
return ;
}
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T = 1;
while(T --) Main();
return fflush(0), 0;
}

浙公网安备 33010602011771号