题解:AT_abc353_e [ABC353E] Yet Another Sigma Problem
字典树模板题。
Code
先贴上字典树板子的代码。
#include<bits/stdc++.h>
using namespace std;
int t,n,q,tree[3000010][71],cnt[3000010],c;
char s[3000010];
int num(char x){
if(x>='A'&&x<='Z')return x-'A';
if(x>='a'&&x<='z')return x-'a'+26;
if(x>='0'&&x<='9')return x-'0'+52;
}
void insert(char str[]){
int now=0,len=strlen(str);
for(int i=0;i<len;i++){
int numer=num(str[i]);
if(!tree[now][numer])tree[now][numer]=++c;
now=tree[now][numer];
cnt[now]++;
}
}
int finding(char str[]){
int now=0,len=strlen(str);
for(int i=0;i<len;i++){
int numer=num(str[i]);
if(!tree[now][numer])return 0;
now=tree[now][numer];
}
return cnt[now];
}
int main(){
cin>>t;
while(t--){
for(int i=0;i<=c;i++){
for(int j=0;j<=70;j++){
tree[i][j]=0;
}
}
for(int i=0;i<=c;i++)cnt[i]=0;
c=0;
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>s;
insert(s);
}
for(int i=1;i<=q;i++){
cin>>s;
cout<<finding(s)<<endl;
}
}
return 0;
}
不难发现,我们为了找出有多少个 前缀包含 ,使用了 数组。
本题其实也差不多。
先附上代码。
#include<bits/stdc++.h>
using namespace std;
int t,n,q,tree[3000010][71],cnt[3000010],c;
char s[3000010];
int num(char x) {
if(x>='A'&&x<='Z')return x-'A';
if(x>='a'&&x<='z')return x-'a'+26;
if(x>='0'&&x<='9')return x-'0'+52;
}
void insert(char str[]) {
int now=0,len=strlen(str);
for(int i=0; i<len; i++) {
int numer=num(str[i]);
if(!tree[now][numer])tree[now][numer]=++c;
now=tree[now][numer];
cnt[now]++;
}
}
int main() {
for(int i=0; i<=c; i++) {
for(int j=0; j<=70; j++) {
tree[i][j]=0;
}
}
for(int i=0; i<=c; i++)cnt[i]=0;
c=0;
cin>>n;
for(int i=1; i<=n; i++) {
cin>>s;
insert(s);
}
long long ans=0;
for(int i=1;i<=c;i++){
ans+=1ll*cnt[i]*(cnt[i]-1)/2;
}
cout<<ans;
return 0;
}
Idea
对于样例
3
abc ard are
可以建字典树如下:

首先我们对于 a 点,有 个字符串共同经过这个点,所以会有 组字符串组对这个 a 产生贡献(让答案加 )。
再看 r 点,有 个字符串共同经过这个点,所以会有 组字符串组对这个 r 产生贡献。
再手搓几组样例,推广一下结论:有 个字符串共同经过一个点,则就有 的字符串组对它产生贡献。
所以我们只需要建树求出 数组(即每个点经过字符串的数量),就可 地求出答案了。
代码见上。
Tips
- 本题答案也可能爆
int。 - 如果要实现
int整数与int整数相乘得到long long整数,需要乘1ll(即long long类型下的 ),否则系统仍会按照int型计算而导致爆int。

浙公网安备 33010602011771号