传送门

考试的时候只来得及糊了个\(n^4\)的暴力,结果考完发现\(n^2\)比\(n^4\)还好写

题意就是就是要求把一堆字符串的前后缀拼起来之后在原串中出现了多少次

然而前后缀可以有很多,再枚举组合就炸没了

先考虑\(n^2\) 写法:

可以先预处理出所有前后缀,分别扔到map里

枚举原串中的每一个位置作为连接点,向前/后分别枚举长度,累加匹配到的前/后缀个数,最后乘起来

发现瓶颈在于枚举长度,考虑优化(以后缀为例

根据题解提示,首先发现所有匹配到的后缀都一定被最长的那个包含,而且能匹配上的长度还有单调性

所以如果能在每个后缀上挂载一个它包含的所有更短后缀的信息,就可以直接二分出能匹配的最长后缀,并利用挂载的信息完成统计

至于具体实现,因为还要统计它包含的后缀的信息,所以可以建棵trie树

统计的时候在trie树上跑遍dfs就可以了

有个小细节:这里二分最长匹配长度的时候是check这个hash值在不在unordered_map中,所以一定要用mp.find(),否则自动创建了就会炸锅

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ull unsigned long long
#define ll long long
//#define int long long inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
} int sl, m;
char s[N], a[3005][5005], st[N];
char* b[N];
int len[N];
const ll base=13131, mod=1206927149;
ll h[N], sh[3005][5005], p[N]; namespace force{
ll ans;
inline ll hashing(ll* h, int l, int r) {return ((h[r]-h[l-1]*p[r-l+1]%mod)%mod+mod)%mod;}
void solve() {
//cout<<double(sizeof(sh)*2)/1024/1024<<endl;
p[0]=1;
for (int i=1; i<N; ++i) p[i]=p[i-1]*base%mod;
for (int i=1; i<=sl; ++i) h[i]=(h[i-1]*base%mod+s[i])%mod;
for (int i=1; i<=m; ++i)
for (int j=1; j<=len[i]; ++j)
sh[i][j]=(sh[i][j-1]*base%mod+a[i][j])%mod;
for (int i=1; i<=m; ++i)
for (int l1=1; l1<=len[i]; ++l1) {
ll t = hashing(sh[i], len[i]-l1+1, len[i]);
//cout<<"t: "<<t<<endl;
//cout<<"try: "; for (int k=len[i]-l1+1; k<=len[i]; ++k) cout<<a[i][k]; cout<<endl;
for (int pos=l1; pos<=sl; ++pos) {
//for (int k=pos-l1+1; k<=pos; ++k) cout<<s[k]; cout<<' '<<hashing(h, pos-l1+1, pos)<<' '<<t<<' '; cout<<endl;
if (hashing(h, pos-l1+1, pos)==t) {
//cout<<"match1: "<<i<<' '<<l1<<' '; for (int k=len[i]-l1+1; k<=len[i]; ++k) cout<<a[i][k]; cout<<endl;
for (int j=1; j<=m; ++j)
for (int l2=1; l2<=min(len[j], sl-pos); ++l2) {
ll t2=hashing(sh[j], 1, l2);
if (hashing(h, pos+1, pos+l2)==t2) ++ans;
}
}
}
}
printf("%lld\n", ans);
exit(0);
}
} namespace task1{
unordered_map<ull, ll> mp;
ll ans;
inline ll hashing(ll* h, int l, int r) {return ((h[r]-h[l-1]*p[r-l+1]%mod)%mod+mod)%mod;}
void solve() {
//cout<<double(sizeof(sh)*2)/1024/1024<<endl;
p[0]=1;
for (int i=1; i<N; ++i) p[i]=p[i-1]*base%mod;
for (int i=1; i<=sl; ++i) h[i]=(h[i-1]*base%mod+s[i])%mod;
for (int i=1; i<=m; ++i)
for (int j=1; j<=len[i]; ++j)
sh[i][j]=(sh[i][j-1]*base%mod+a[i][j])%mod; for (int i=1; i<=m; ++i)
for (int j=1; j<=len[i]; ++j)
++mp[hashing(sh[i], 1, j)]; for (int i=1; i<=m; ++i)
for (int l1=1; l1<=len[i]; ++l1) {
ll t = hashing(sh[i], len[i]-l1+1, len[i]), t2;
for (int pos=l1; pos<=sl; ++pos) {
if (hashing(h, pos-l1+1, pos)==t) {
for (int j=pos+1; j<=sl; ++j) {
t2 = hashing(h, pos+1, j);
if (mp.find(t2)!=mp.end())
ans+=mp[t2];
}
}
}
}
printf("%lld\n", ans);
exit(0);
}
} namespace task2{
ull h[N], p[N], sh[3005][5005];
unordered_map<ull, ll> mp1, mp2;
ll ans;
inline ull hashing(ull* h, int l, int r) {return h[r]-h[l-1]*p[r-l+1];}
void solve() {
p[0]=1;
for (int i=1; i<N; ++i) p[i]=p[i-1]*base;
for (int i=1; i<=sl; ++i) h[i]=h[i-1]*base+s[i];
for (int i=1; i<=m; ++i)
for (int j=1; j<=len[i]; ++j)
sh[i][j]=sh[i][j-1]*base+a[i][j]; for (int i=1; i<=m; ++i)
for (int j=len[i]; j; --j)
++mp1[hashing(sh[i], j, len[i])]; for (int i=1; i<=m; ++i)
for (int j=1; j<=len[i]; ++j)
++mp2[hashing(sh[i], 1, j)]; ll t1, t2, t;
for (int i=2; i<=sl; ++i) {
t1=0, t2=0;
for (int j=i-1; j; --j) {
t=hashing(h, j, i-1);
if (mp1.find(t)!=mp1.end()) t1+=mp1[t];
}
for (int j=i; j<=sl; ++j) {
t=hashing(h, i, j);
if (mp2.find(t)!=mp2.end()) t2+=mp2[t];
}
ans+=t1*t2;
} printf("%lld\n", ans);
exit(0);
}
} namespace task{
unordered_map<ull, ll> mp1, mp2;
ll ans;
ull h1[N], h2[N], p[N];
inline ull hashing(ull* h, int l, int r) {return h[r]-h[l-1]*p[r-l+1];}
inline ull hash2(int r, int l) {return h2[r]-h2[l+1]*p[l-r+1];}
const int SIZE=N*50;
int tot, son[SIZE][26], cnt[SIZE], size[SIZE];
ull sh[SIZE];
#define son(a, b) son[a][b]
struct trie1{
int rot;
trie1(){rot=++tot;}
void ins(char* s, int len) {
int p=rot, u;
ll h=0;
for (int dep=1; dep<=len; ++dep) {
u=son(p, s[dep]-'a');
h=h*base+s[dep];
if (!u) {son(p, s[dep]-'a')=u=++tot; sh[u]=h;}
++cnt[u];
p=u;
}
}
void dfs(int u) {
//cout<<"dfs "<<u<<endl;
size[u]+=cnt[u];
//if (mp1.find(sh[u])!=mp1.end()) puts("same hashval");
mp1[sh[u]]=size[u];
//cout<<sh[u]<<' '<<size[u]<<endl;
for (int i=0; i<26; ++i)
if (son(u, i)) {
size[son(u, i)]+=size[u];
dfs(son(u, i));
}
}
}tr1;
struct trie2{
int rot;
trie2(){rot=++tot;}
void ins(char* s, int len) {
int p=rot, u;
ll h=0;
for (int dep=len; dep; --dep) {
u=son(p, s[dep]-'a');
h=h*base+s[dep];
if (!u) {son(p, s[dep]-'a')=u=++tot; sh[u]=h;}
++cnt[u];
p=u;
}
}
void dfs(int u) {
//cout<<"dfs "<<u<<endl;
size[u]+=cnt[u];
//if (mp2.find(sh[u])!=mp2.end()) puts("same hashval");
mp2[sh[u]]=size[u];
for (int i=0; i<26; ++i)
if (son(u, i)) {
size[son(u, i)]+=size[u];
dfs(son(u, i));
}
}
}tr2;
void solve() {
for (int i=1; i<=m; ++i) tr1.ins(b[i], len[i]), tr2.ins(b[i], len[i]);
//cout<<"tot: "<<tot<<endl;
p[0]=1;
for (int i=1; i<N; ++i) p[i]=p[i-1]*base;
for (int i=1; i<=sl; ++i) h1[i]=h1[i-1]*base+s[i];
for (int i=sl; i; --i) h2[i]=h2[i+1]*base+s[i];
tr1.dfs(tr1.rot); tr2.dfs(tr2.rot);
ll t1, t2;
int l, r, mid;
for (int i=2; i<=sl; ++i) {
l=0, r=i;
while (l<=r) {
mid=(l+r)>>1;
if (mp2.find(hash2(i-mid+1, i-1))!=mp2.end()) l=mid+1;
else r=mid-1;
}
if (mp2.find(hash2(i-l+2, i-1))==mp2.end()) continue;
t1=mp2[hash2(i-l+2, i-1)]; //, cout<<"test: "<<i-l+2<<' '<<i-1<<endl;
//cout<<"l: "<<l-1<<endl;
//cout<<t1<<endl; l=0, r=sl-i;
while (l<=r) {
mid=(l+r)>>1;
if (mp1.find(hashing(h1, i, i+mid))!=mp1.end()) l=mid+1;
else r=mid-1;
}
if (mp1.find(hashing(h1, i, i+l-1))==mp1.end()) continue;
t2=mp1[hashing(h1, i, i+l-1)];
//cout<<"l: "<<l-1<<endl;
//cout<<t2<<endl; ans+=t1*t2;
//cout<<i<<" += "<<t1*t2<<' '<<t1<<' '<<t2<<endl;
}
printf("%lld\n", ans);
exit(0);
}
} signed main()
{
scanf("%s%d", s+1, &m); sl=strlen(s+1);
for (int i=1; i<=m; ++i) {
scanf("%s", st+1);
len[i]=strlen(st+1);
b[i]=new char[len[i]+3];
memcpy(b[i]+1, st+1, sizeof(char)*(len[i]+1));
}
//if (m<=50) force::solve();
//else task1::solve();
//task2::solve();
task::solve(); return 0;
}

题解 string的更多相关文章

  1. [LeetCode 题解]: String to Interger (atoi)

    Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input cases. ...

  2. LeetCode题解——String to Integer(atoi)

    题目: 字符串转换为数字. 解法: 这道题的意思是要考虑到,如果有前置的空字符,则跳过:如果超出数字范围,则返回最大/最小整数:如果碰到第一个不能转换的字符,则返回. 代码: class Soluti ...

  3. P1980 计数问题 - 记录

    P1980 计数问题 题目描述 试计算在区间 1 到 n的所有整数中,数字x(0 ≤ x ≤ 9)共出现了多少次?例如,在 1到11中,即在 1,2,3,4,5,6,7,8,9,10,11中,数字1出 ...

  4. luogu题解P1032字串变换--BFS+STL:string骚操作

    题目链接 https://www.luogu.org/problemnew/show/P1032 分析 这题本来很裸的一个BFS,发现其中的字符串操作好烦啊.然后就翻大佬题解发现用STL中的strin ...

  5. 【题解】Rusty String [CF827E]

    [题解]Rusty String [CF827E] 传送门:\(\text{Rusty String}\) \(\text{[CF827E]}\) [题目描述] 多组数据,每组数据给出一个由 \(V, ...

  6. 杭电多校HDU 6586 String(预处理 + 贪心)题解

    题意: 给你一个串,现需要你给出一个子序列,满足26个约束条件,\(len(A_i) >= L_i\) 且 \(len(A_i) <= R_i\), \(A_i\)为从a到z的26个字母. ...

  7. [LeetCode] Decode String 题解

    题目 题目 s = "3[a]2[bc]", return "aaabcbc". s = "3[a2[c]]", return " ...

  8. LeetCode 题解之Reverse Words in a String

    1.题目描述 2.问题分析 使用一个vector存储每个单词. 3.代码 void reverseWords(string &s) { vector<string> v; for ...

  9. LeetCode题解之Number of Segments in a String

    1.题目描述 2.题目分析 找到字符串中的空格即可 3.代码 int countSegments(string s) { ){ ; } vector<string> v; ; i < ...

随机推荐

  1. ARM汇编指令-STM32单片机启动

    EQU 给数字常量取一个符号名,相当于c中的define. AREA  告诉汇编器汇编一个新的代码段. SPACE 分配内存空间. PRESERVE   当前文件堆栈按照8字节对齐. EXPORT 声 ...

  2. VMware中的虚机如何挂载U盘

    1.将U盘插入到宿主机上. 2.在VM Client上,点击宿主机,右键,扫描存储设备(目的是为了发现新USB存储) 3.在需要的虚拟机上编辑配置,添加硬件,添加USB设备(如果不进行以上2个步骤,此 ...

  3. 「AGC021E」Ball Eat Chameleons

    「AGC021E」Ball Eat Chameleons 考虑如何判定一个合法的颜色序列. 不妨设颜色序列中有 \(R\) 个红球,\(B\) 个蓝球,所以有 \(R+B=k\). 考虑分情况讨论: ...

  4. springboot-8-企业开发

    一.邮件发送 流程: mbqplwpheeyvgdjh 首先需要开启POS3/SMTP服务,这是一个邮件传输协议 点击开启 导入依赖 <!--mail--> <dependency& ...

  5. Java-数组有关

    1.复制数组 复制数组主要有三类方法: 1.使用循环语句逐个赋值数组元素 2.使用System类中的静态方法arraycopy 3.使用clone方法复制数组 对于2,详述如下: arraycopy( ...

  6. Dubbo的优雅下线原理分析

    文/朱季谦 Dubbo如何实现优雅下线? 这个问题困扰了我一阵,既然有优雅下线这种说法,那么,是否有非优雅下线的说法呢? 这,还真有. 可以从linux进程关闭说起,其实,我们经常使用到杀进程的指令背 ...

  7. selenium 配置ie11 浏览器

    1.IEDriverServer下载与配置 用淘宝的镜像地址:https://npm.taobao.org/mirrors/selenium/. 选3.0版本的  IEDriverServer_x64 ...

  8. vulnhub-DC:3靶机渗透记录

    准备工作 在vulnhub官网下载DC:1靶机www.vulnhub.com/entry/dc-3,312/ 导入到vmware 导入的时候遇到一个问题 解决方法: 点 "虚拟机" ...

  9. C++第三十九篇 -- 研究一下Windows驱动开发(二)-- 驱动程序中重要的数据结构

    数据结构是计算机程序的核心,I/O管理器定义了一些数据结构,这些数据结构是编写驱动程序时所必须掌握的.驱动程序经常要创建和维护这些数据结构的实例. 一.驱动对象(DRIVER_OBJECT) 每个驱动 ...

  10. 深入刨析tomcat 之---第6篇 how tomcat works 第5章 容器实现原理

    writedby 张艳涛