[atARC141F]Well-defined Abbreviation

T=Si,不断删除其任意子串{Sjij},最终应有T{Si,}

关于该过程的实现,考虑建立AC自动机,并从前往后依次加入字符

若当前节点存在后缀为某子串,则删去该后缀,并跳到剩余部分对应位置

T=,则删除Si可以以该过程代替,不妨去掉Si,且这并不影响其余串

在此基础上,对于剩下的这些串(最终T=Si),即两两不成子串关系

结论:TA,B,C(其中AC且均非空)满足AB,BC{Si}

关于充分性,取T=ABC即可(注意到AC均不存在{Si}中的子串)

关于必要性,若满足此条件,对|T|从小到大归纳,并取出T中所有{Si}的子串

注意到对应位置两两不交(不成子串关系&不存在A,B,C),进而可以将这些全部删除

具体的,记Ti表示删去第i个串,T0表示全部删除,f(T)表示T所有可能的结果并

显然f(T0)f(Ti),根据归纳两者大小均为1,进而f(T)=f(Ti)=f(T0),即得证

关于该条件的判定,枚举其中AB对应串即后缀(借助fail指针)

若对应子树内存在多个串,显然总存在CA,否则哈希比较两者即可

时间复杂度为o(|si|),可以通过

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 2000005
 4 #define mod 998244353
 5 #define base 47
 6 #define ll long long
 7 int n,V,l,k,dep[N],ed[N],nex[N],pos[N],vis[N],cnt[N],ch[N][4];
 8 char s[N];queue<int>q;vector<int>v[N];
 9 void init(){
10     V=1;
11     memset(ch,0,sizeof(ch));
12 }
13 void add(int id){
14     k=1;
15     for(int c:v[id]){
16         if (!ch[k][c])ch[k][c]=++V,dep[V]=dep[k]+1;
17         k=ch[k][c];
18     }
19 }
20 void build(){
21     for(int i=0;i<4;i++){
22         if (!ch[1][i])ch[1][i]=1;
23         else nex[ch[1][i]]=1,q.push(ch[1][i]);
24     }
25     while (!q.empty()){
26         int k=q.front();q.pop();
27         if (!ed[k])ed[k]=ed[nex[k]];
28         for(int i=0;i<4;i++){
29             if (!ch[k][i])ch[k][i]=ch[nex[k]][i];
30             else nex[ch[k][i]]=ch[nex[k]][i],q.push(ch[k][i]);
31         }
32     } 
33 }
34 int main(){
35     scanf("%d",&n),init();
36     for(int i=1;i<=n;i++){
37         scanf("%s",s),l=strlen(s);
38         for(int j=0;j<l;j++)v[i].push_back(s[j]-'A');
39         add(i),ed[k]=l;
40     }
41     build();
42     for(int i=1;i<=n;i++){
43         l=0,k=pos[0]=1;
44         for(int c:v[i]){
45             k=ch[k][c];
46             if ((!ed[k])||(ed[k]==v[i].size()))pos[++l]=k;
47             else l-=ed[k]-1,k=pos[l];
48         }
49         if ((l)&&(l<v[i].size())){
50             printf("Yes\n");
51             return 0;
52         }
53         vis[i]=(l==v[i].size());
54     }
55     init();
56     for(int i=1;i<=n;i++)
57         if (vis[i])add(i);
58     build();
59     for(int i=1;i<=n;i++)
60         if (vis[i]){
61             l=0,k=pos[0]=1;
62             for(int c:v[i])k=pos[++l]=ch[k][c],cnt[k]++;
63             ed[pos[l]]=0;
64             for(l--;l;l--)ed[pos[l]]=((ll)base*ed[pos[l+1]]+v[i][l]+1)%mod;
65         }
66     for(int i=1;i<=n;i++)
67         if (vis[i]){
68             int s=1;l=pos[0]=0,k=1;
69             for(int c:v[i]){
70                 l++,k=ch[k][c];
71                 pos[l]=(pos[l-1]+(ll)s*(c+1))%mod,s=(ll)base*s%mod;
72             }
73             for(k=nex[k];k>1;k=nex[k])
74                 if ((cnt[k]>1)||(ed[k]!=pos[l-dep[k]])){
75                     printf("Yes\n");
76                     return 0;
77                 }
78         }
79     printf("No\n");
80     return 0;
81 } 
View Code
复制代码

 

posted @   PYWBKTDA  阅读(82)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
历史上的今天:
2021-07-17 [cf1349D]Slime and Biscuits
2021-07-17 [bzoj3569]DZY Loves Chinese II
点击右上角即可分享
微信分享提示