题目地址
题目思路很明确,求t上每个位置以其结尾的串有多少个,以其为开头的串有多少个,然后遍历一遍算出贡献就行了。最后正解的思路非常简单,但我硬是整了几个假算法浪费时间,下面说一下我的心路历程。
第一层:求开头?求结尾?这不是弱智kmp吗?敲敲敲…一遍过样例,就这也有2400?
然后t了。仔细一想,Kmp复杂度是o(s+t),那么对每一个si跑一遍kmp复杂度不就是o(nt+s)了吗,以下是t了的代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <time.h>
#include <map>
#include <algorithm>
#include <fstream>
//#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000000+100;
const int INF = 0x7fffffff;
const ll mod = 998244353;
const ll mod1 = 998244353;
const ll base = 137;
const double Pi = acos(-1.0);
const int G = 3;
int nxt[maxn];
void getnxt(char *s, int n)
{int j = 0;for (int i = 2; i <= n; i++){while (j && s[i] != s[j + 1])j = nxt[j];if (s[j + 1] == s[i])j++;nxt[i] = j;}
}
int vis1[maxn];
int vis2[maxn];
ll ans=0;
void kmp(char *s, char *t, int n, int m)
{int j = 0;for (int i = 1; i <= n; i++){while (j > 0 && t[j + 1] !=s[i])j = nxt[j];if (t[j + 1] == s[i])j++;if (j == m){ans+=vis2[i-m];ans+=vis1[i+1];vis1[i-m+1]++;vis2[i]++;j = nxt[j];}}
}
char s[maxn];
char t[maxn];
int main()
{scanf("%s",s+1);int len1=strlen(s+1);getnxt(s,len1);int n;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s",t+1);int len2=strlen(t+1);kmp(s,t,len1,len2);}cout<<ans<<endl;// system("pause");
}

第二层:这里涉及到多个串,那么我可以建个ac自动机,然后建个fail树,在自动机上跑t,每到一个点,就相当于也跑过了其fail树的所有祖先节点,那么对于以这个位置为结尾的串的长度就是这所有的祖先节点。那么怎么更新信息呢,我一想,可以先暂时不管祖先,先把所有相应的节点跑到t哪个位置标记好,然后最后从叶子往上启发式合并,这样一定没问题。然后t了,仔细一想,启发式合并的复杂度是没问题,但更新信息的时候还是对合并后的整个集合更新,那复杂度不又回去了?以下是t了的代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <time.h>
#include <map>
#include <algorithm>
#include <fstream>
//#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000000+100;
const int INF = 0x7fffffff;
const ll mod = 998244353;
const ll mod1 = 998244353;
const ll base = 137;
const double Pi = acos(-1.0);
const int G = 3;
int trie[maxn][30], fail[maxn],sz;
int val[maxn];
void insert(char *s,int id)
{int u = 0, len = strlen(s+1);for (int i = 1; i <= len; i++){if (!trie[u][s[i] - 'a']){trie[u][s[i] - 'a'] = ++sz;memset(trie[sz], 0, sizeof(trie[sz]));}u = trie[u][s[i] - 'a'];}val[u]++;
}void getFail()
{queue<int> Q;fail[0] = 0;for (int i = 0; i < 26; i++)if (trie[0][i]){fail[trie[0][i]] = 0;Q.push(trie[0][i]);}while (!Q.empty()){int u = Q.front();Q.pop();// val[u] += val[fail[u]]; //看具体题目,不一定要加for (int i = 0; i < 26; i++){if (!trie[u][i])trie[u][i] = trie[fail[u]][i];else{fail[trie[u][i]] = trie[fail[u]][i];Q.push(trie[u][i]);}}}
}
char t[maxn];
char s[maxn];
vector<int>v[maxn];
set<int>se[maxn];
ll vis1[maxn];
ll vis2[maxn];
int dep[maxn];
void dfs(int x)
{for(auto i:v[x]){dep[i]=dep[x]+1;dfs(i);if(se[i].size()>se[x].size()){swap(se[i],se[x]);}for(auto j:se[i]) se[x].insert(j);}for(auto i:se[x]) //t的主要地方,这个地方有没有启发式合并都没意义了。{vis2[i]+=val[x];vis1[i-dep[x]+1]+=val[x];}
}
int main()
{scanf("%s",t+1);int len=strlen(t+1);int n;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s",s+1);insert(s,i);}getFail();for(int i=1;i<=sz;i++){v[fail[i]].push_back(i);}int now=0;for(int i=1;i<=len;i++){now=trie[now][t[i]-'a'];se[now].insert(i);}dfs(0);ll ans=0;for(int i=1;i<=len;i++){ans+=vis2[i]*vis1[i+1];}cout<<ans<<endl;// system("pause");
}

第三层:继续刚才的思路,发现其实每跑到一个位置,其结尾位置是固定的,更新的信息就是祖先的权值和,这个很好写,dfs一遍就行,那结尾标记就算完了,开始标记怎么办呢?我再建一个反向的ac自动机,然后反着跑t不就行了,于是正解就是跑两边ac自动机。一开始数组全开了1e6大小结果mle了,以为这个方法也别卡了,差点崩溃,后来改成2e5就过了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <time.h>
#include <map>
#include <algorithm>
#include <fstream>
//#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 200000 + 100;
const int INF = 0x7fffffff;
const ll mod = 998244353;
const ll mod1 = 998244353;
const ll base = 137;
const double Pi = acos(-1.0);
const int G = 3;
struct node
{vector<int> v[maxn];int trie[maxn][30], fail[maxn], sz;int val[maxn];void insert(char *s, int id){int u = 0, len = strlen(s + 1);for (int i = 1; i <= len; i++){if (!trie[u][s[i] - 'a']){trie[u][s[i] - 'a'] = ++sz;memset(trie[sz], 0, sizeof(trie[sz]));}u = trie[u][s[i] - 'a'];}val[u]++;}void getFail(){queue<int> Q;fail[0] = 0;for (int i = 0; i < 26; i++)if (trie[0][i]){fail[trie[0][i]] = 0;Q.push(trie[0][i]);}while (!Q.empty()){int u = Q.front();Q.pop();// val[u] += val[fail[u]]; //看具体题目,不一定要加for (int i = 0; i < 26; i++){if (!trie[u][i])trie[u][i] = trie[fail[u]][i];else{fail[trie[u][i]] = trie[fail[u]][i];Q.push(trie[u][i]);}}}}ll sum[maxn];void dfs(int x){sum[x] += val[x];for (auto i : v[x]){sum[i] += sum[x];dfs(i);}}
}ac1,ac2;
char t[maxn];
char s[maxn];
ll vis1[maxn];
ll vis2[maxn];
int main()
{scanf("%s", t + 1);int len = strlen(t + 1);int n;scanf("%d", &n);for (int i = 1; i <= n; i++){scanf("%s", s + 1);ac1.insert(s, i);int len1=strlen(s+1);for(int i=1;i<=len1/2;i++){swap(s[i],s[len1-i+1]);}ac2.insert(s,i);}ac1.getFail();ac2.getFail();for (int i = 1; i <= ac1.sz; i++){ac1.v[ac1.fail[i]].push_back(i);}ac1.dfs(0);for (int i = 1; i <= ac2.sz; i++){ac2.v[ac2.fail[i]].push_back(i);}ac2.dfs(0);int now = 0;for (int i = 1; i <= len; i++){now = ac1.trie[now][t[i] - 'a'];vis2[i] += ac1.sum[now];}now=0;for(int i=len;i>=1;i--){now = ac2.trie[now][t[i] - 'a'];vis1[i] += ac2.sum[now];}ll ans = 0;for (int i = 1; i <= len; i++){ans += 1ll * vis2[i] * vis1[i + 1];}printf("%lld\n", ans);//  system("pause");
}

E. You Are Given Some Strings...(AC自动机)相关推荐

  1. HDU 6208 The Dominator of Strings AC自动机

    题目链接:HDU 6208 The Dominator of Strings Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 65535 ...

  2. CF1202 - E. You Are Given Some Strings...(AC自动机)

    题目链接 题意 1个匹配串TTT,nnn个模式串SSS,求∑i=1n∑j=1nF(T,Si+Sj)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}F(T,S_i+S ...

  3. hdu6208 The Dominator of Strings(AC自动机)

    题意: 给定n个串,问其中是否存在一个串,满足其他串都是它的子串. 如果存在这样的串,输出这个串,否则输出No 数据范围:所有串长度不超过1e5 解法: 答案串一定是最长的串, 如果只有一个最长的串, ...

  4. HDU - 3247 Resource Archiver (AC自动机,状压dp)

    \(\quad\)Great! Your new software is almost finished! The only thing left to do is archiving all you ...

  5. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

  6. 2018北京ICPC H. Approximate Matching(AC自动机+DP)

    H : Approximate Matching 时间限制:1000ms,单点时限:1000ms,内存限制:512MB 描述 String matching, a common problem in ...

  7. AC自动机笔记与例题整理

    TP KMP AC自动机建树/图 最后就是例题时间: 搜索关键词 单词 设计密码 修复DNA Codeforces16届黑龙江省赛E题 洛谷:阿狸打字机(经典自动机,fail树上数据结构维护信息) [ ...

  8. HDU 6208【假AC自动机+string方法】

    题目链接:http://acm.hdu.edu.cn/listproblem.php?vol=1 The Dominator of Strings Time Limit: 3000/3000 MS ( ...

  9. Aho-Corasick 多模式匹配算法(AC自动机) 的算法详解及具体实现

    多模式匹配 多模式匹配就是有多个模式串P1,P2,P3-,Pm,求出所有这些模式串在连续文本T1-.n中的所有可能出现的位置. 例如:求出模式集合{"nihao","ha ...

最新文章

  1. hystrix 配置 不生效_12、Feign整合断路器Hystrix
  2. Modesim 仿真 ERRO VSIM-19
  3. Android访问瓦片地图 费流量,瓦片地图注意事项
  4. JZOJ 3899. 【NOIP2014模拟】逻辑的连通性
  5. 同时阅读多个pdf文档怎么办?
  6. 「数据ETL」从数据民工到数据白领蜕变之旅(六)-将Python的能力嫁接到SSIS中...
  7. AnalyticDB for MySQL 3.0基础版重磅发布
  8. [saiku] 使用 Apache Phoenix and HBase 结合 saiku 做大数据查询分析
  9. Apache 简单设置虚拟主机
  10. Event Listener's Adapter Classes
  11. 线上支付之----网关支付、银联代扣通道、快捷支付、银行卡支付等网上常见支付方式接口说明!!
  12. 双人贪吃蛇@botzone算法设计
  13. 迅雷一些版本下载链接
  14. 科三 二十里铺(带视频)
  15. python父亲节礼物送什么_父亲节送什么礼物好
  16. gbase xdm管理控制台说明
  17. 2023英伟达显卡排名天梯图(已更新)
  18. cd28v2虚拟服务器,科技知识:华为荣耀CD28v2路由器初始密码
  19. 规模化交付OpenStack和Kubernetes,Airship成为顶级OSF项目
  20. [转]四大开源商业智能平台大比拼[http://database.ctocio.com.cn/analysis/289/7610289.shtml]

热门文章

  1. c语言和python语言分别是一种什么语言_作为入门语言,C语言和Python哪一种更值得选择?...
  2. MATLAB从2018到2019版本-randint函数,modem函数的变更
  3. 大仙来了【20年复试上机真题】
  4. 以技术共生智变,创商业共赢质变 华为云生态峰会盛大启幕
  5. Advances and Open Problems in Federated Learning——4.Preserving the Privacy of User Data翻译
  6. mysql异地多活方案_最易懂的数据库异地多活方案
  7. SQLLDR-CTL文件导入oracle:字段控制(截取)
  8. 服务器远程如何更改端口,如何修改windows2003默认的远程端口
  9. fastapi(二十)-大型项目文件结构
  10. python做网站开发_【Python成长之路】从 零做网站开发 -- 基于Flask和JQuery,实现表格管理平台...