[atARC141F]Well-defined Abbreviation
取,不断删除其任意子串,最终应有
关于该过程的实现,考虑建立AC自动机,并从前往后依次加入字符
若当前节点存在后缀为某子串,则删去该后缀,并跳到剩余部分对应位置
若,则删除可以以该过程代替,不妨去掉,且这并不影响其余串
在此基础上,对于剩下的这些串(最终),即两两不成子串关系
结论:(其中且均非空)满足
关于充分性,取即可(注意到和均不存在中的子串)
关于必要性,若满足此条件,对从小到大归纳,并取出中所有的子串
注意到对应位置两两不交(不成子串关系&不存在),进而可以将这些全部删除
具体的,记表示删去第个串,表示全部删除,表示所有可能的结果并
显然,根据归纳两者大小均为,进而,即得证
关于该条件的判定,枚举其中对应串即后缀(借助指针)
若对应子树内存在多个串,显然总存在,否则哈希比较两者即可
时间复杂度为,可以通过

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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需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