【学习笔记】[ARC141F] Well-defined Abbreviation

字符串啊啊啊

f ( S ) f(S) f(S)表示字符串 S S S对应操作后得到的不同字符串数目。

对于 S i S_i Si,假设其存在一个 j j j满足 S j S_j Sj S i S_i Si的子串,那么 S i S_i Si必然可以用若干 S j S_j Sj来表示,删去 S i S_i Si不会对任何的 f ( S ) f(S) f(S)造成影响。

否则不难想到,如果存在两个串 ( S i , S j ) (S_i,S_j) (Si,Sj)满足 S i = A + B , S j = B + C S_i=A+B,S_j=B+C Si=A+B,Sj=B+C并且 A ≠ C A\ne C A=C,那么不合法。

充分性非常显然。必要性直观上看也是比较显然的(如果两种操作序列操作的区间产生了重叠,那么剩下的串 S ′ S' S也是相同的)。事实上可以用归纳法漂亮的证明。

可以用 hash \text{hash} hash以及 A C AC AC自动机实现。复杂度 O ( n + ∑ s i ) O(n+\sum s_i) O(n+si)

#include<bits/stdc++.h> #define fi first #define se second #define ll long long #define pb push_back #define inf 0x3f3f3f3f #define ull unsigned long long using namespace std; const int P=13331; int n,tot; ull f[2000005],h[2000005]; struct node{ int nxt[4],c,l,fail,ok,len; ull v; }t[2000005]; string s[1000005]; queue<int>Q; vector<string>v; vector<string>v2; ull ask(int l,int r){ return h[r]-h[l-1]*f[r-l+1]; } void extend(string &s){ int l=s.size(); f[0]=1;for(int i=1;i<=l;i++)f[i]=f[i-1]*P,h[i]=h[i-1]*P+s[i-1]; int it=0; for(int i=0;i<l;i++){ if(!t[it].nxt[s[i]-'A'])t[it].nxt[s[i]-'A']=++tot,t[tot].len=i+1; it=t[it].nxt[s[i]-'A']; if(i+1!=l){ ull x=ask(i+2,l); if(!t[it].ok)t[it].ok=1,t[it].v=x; else if(t[it].v!=x)t[it].v=0; } }t[it].c++,t[it].l=l; } void build(){ for(int i=0;i<4;i++){ if(t[0].nxt[i])Q.push(t[0].nxt[i]); }while(Q.size()){ int x=Q.front(),y=t[x].fail;Q.pop(); t[x].c+=t[y].c;if(t[y].c)t[x].l=t[y].l; for(int i=0;i<4;i++){ if(t[x].nxt[i]){ Q.push(t[x].nxt[i]); t[t[x].nxt[i]].fail=t[y].nxt[i]; } else { t[x].nxt[i]=t[y].nxt[i]; } } } } int check(string &s){ int it=0,l=s.size(); for(int i=0;i<l;i++){ it=t[it].nxt[s[i]-'A']; if(t[it].c>1||t[it].c>0&&i+1!=l)return 0; }return 1; } void check2(string &s){ int it=0,l=s.size(); f[0]=1;for(int i=1;i<=l;i++)f[i]=f[i-1]*P,h[i]=h[i-1]*P+s[i-1]; for(int i=0;i<l;i++){ it=t[it].nxt[s[i]-'A']; }for(it=t[it].fail;it;it=t[it].fail){ if(t[it].ok&&t[it].v!=ask(1,l-t[it].len)){ cout<<"Yes"; exit(0); } } } stack<int>stk; void check3(string &s){ while(stk.size())stk.pop();stk.push(0); for(int i=0;i<s.size();i++){ int it=stk.top();it=t[it].nxt[s[i]-'A'],stk.push(it); if(t[it].c){ for(int i=1;i<=t[it].l;i++)stk.pop(); } }if(stk.size()!=1){ cout<<"Yes"; exit(0); } } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n;for(int i=1;i<=n;i++)cin>>s[i],extend(s[i]); build(); for(int i=1;i<=n;i++){ if(check(s[i]))v.pb(s[i]); else v2.pb(s[i]); }memset(t,0,sizeof t),tot=0; for(int i=0;i<v.size();i++)extend(v[i]); build(); for(int i=0;i<v.size();i++)check2(v[i]); for(int i=0;i<v2.size();i++)check3(v2[i]); cout<<"No"; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530073.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(12)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示