原题连接
问题描述
给定出一大堆字符串,要求任意两个字符串拼在一起在 t t t串中出现的个数之和。有多任意呢?只要满足这两个字符串都是这一大堆的字符串中的就行(拼起来一样的两组算两个,同一个字符串也可以拼起来)。
说实话,我这概括的描述比洛谷的描述还多
解决问题
看到一大堆字符串要匹配,二话不说,先看漏要两个字符串拼在一起的条件,跑一遍 A C AC AC自动机。那么两个字符串拼到一起呢?反着跑一遍再接上不就行了嘛。怎么接上呢?记录正着匹配和反着匹配在 i i i结束匹配的数量,那就是小学数学——乘法原理了。注意,这个题要用优化的 A C AC AC自动机,否则你就 T L E TLE TLE了。
丑陋代码
#include<bits/stdc++.h>
using namespace std;
const int NN=2e5+4;
string s[NN];
int ne[NN][2],st[NN][30][2],sum[NN][2],res[NN][2],idx[2],len;
void insert(string x,int k)
{
int len=x.size(),u=0;
for(int i=0;i<len;i++)
{
if(!st[u][x[i]-'a'][k])
st[u][x[i]-'a'][k]=++idx[k];
u=st[u][x[i]-'a'][k];
}
sum[u][k]++;
}
void before_ACAM()
{
queue<int>q;
for(int k=0;k<2;k++)
{
for(int i=0;i<26;i++)
if(st[0][i][k])
q.push(st[0][i][k]);
while(q.size())
{
int t=q.front();
q.pop();
for(int i=0;i<26;i++)
{
int u=st[t][i][k];
if(u)
{
ne[u][k]=st[ne[t][k]][i][k];
sum[u][k]+=sum[ne[u][k]][k];
q.push(u);
}
else
st[t][i][k]=st[ne[t][k]][i][k];
}
}
}
}
void ACAM(string t,int k)
{
int u=0;
for(int i=0;i<len;i++)
{
u=st[u][t[i]-'a'][k];
res[i][k]=sum[u][k];
}
}
int main()
{
string t;
int n;
cin>>t>>n;
len=t.size();
for(int i=1;i<=n;i++)
{
cin>>s[i];
insert(s[i],0);
reverse(s[i].begin(),s[i].end());
insert(s[i],1);
}
before_ACAM();
ACAM(t,0);
reverse(t.begin(),t.end());
ACAM(t,1);
long long ans=0;
for(int i=0;i<len-1;i++)
ans+=1ll*res[i][0]*res[len-i-2][1];
cout<<ans;
return 0;
}
PS
这个题我很想用 s c a n f scanf scanf的,但是这就要用 c h a r char char存,然后就出大问题。至于是什么大问题,你们写写就知道了。
PPS
题目名字最后的三个点让我误以为 C F CF CF有题目名称没展示全的题 Q w Q QwQ QwQ。
PPPS
这个题我跑完第一遍 A C AC AC自动机就马上懵了。然后我就努力看题解推算,最后连抄带写终于写完了。
PPP…S
还有还有,啊~~~
在某人写到第 1024 1024 1024个 P S PS PS时终于决定不写了,然而写题解的蒟蒻却再也不想看这个题解了。
全剧终。
《蒟蒻造题解的 1024 1024 1024分钟》