P6698-[BalticOI 2020 Day2]病毒【AC自动机,dp,SPFA】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P6698


1|1题目大意

有一个包含0G1的字符集,其中有n种变换,能够将一个字符ai(ai>1)变为一串字符bi,当一个字符串中只剩下01时变换就结束了。

然后给出m个匹配串ci。现在对于每个字符i[2,G1],是否字符i无论变化结束时都含有至少一个匹配串,如果不是,求一个最短的不包含任何匹配串的最终串长度。

保证每个在[2,G1]的字符都能进行变化,匹配串中只包含0/1

ti50,|bi|100,n100,2<Gn+2


1|2解题思路

有匹配的问题,我们先拿所有的ci出来建一棵AC自动机,然后考虑怎么计算每个字符能从哪个状态跳到哪个状态。

注意我们在AC自动机上走状态时不能走到包含匹配串的状态,这样我们可以将无论如何都包含匹配串视为最短不包含匹配串的长度无穷大。

那么我们考虑dp这个最短的长度,设fi,s,t表示字符i经过变换后,能从状态s走到状态t的最短长度。

转移时我们考虑枚举一个变换i,再枚举一个起点s,然后设gj,x表示现在走到bi,j,在状态x时的最短长度,那么转移时就有

gj+1,y=min{gj,x+fbi,j,x,y}

但是会注意到fi,s,t之间的转移并不是一个单向的关系,会发现这是一个和最短路很类似的转移,我们考虑魔改一下SPFA。

我们先把0,1加入队列,然后每次取出队头x,我们把所有包含字符xbi都拿出来跑一次g,如果这次跑出来的g能够更新fai,s,t,那么我们就把ai入队(如果之前ai不在队列中)。

我们视SPFA的复杂度为O(n2),记AC自动机状态数为k,每做一次转移应该是O(|bi|k3),那么这题中SPFA的复杂度应该就是O(G|bi|k3),实际上跑起来常数会很小,可以通过本题。


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #define ll long long using namespace std; const ll N=105,inf=1e18; ll G,n,m,a[N],f[N][N][N],g[N][52]; ll cnt,ch[N][2],fail[N];bool ed[N],v[N]; queue<int> q;vector<int> b[N],T[N]; void ins(ll n){ ll x=0; for(ll i=1,c;i<=n;i++){ scanf("%lld",&c); if(!ch[x][c])ch[x][c]=++cnt; x=ch[x][c]; } ed[x]=1;return; } void getfail(){ for(ll i=0;i<2;i++) if(ch[0][i])q.push(ch[0][i]); while(!q.empty()){ ll x=q.front();q.pop(); ed[x]|=ed[fail[x]]; for(ll i=0;i<2;i++){ if(ch[x][i]){ fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]); } else ch[x][i]=ch[fail[x]][i]; } } return; } bool solve(int i){ bool flag=0; for(ll s=0;s<=cnt;s++){ if(ed[s])continue; memset(g,0x3f,sizeof(g));g[0][s]=0; for(ll j=0;j<b[i].size();j++){ for(ll x=0;x<=cnt;x++){ if(g[j][x]>=inf)continue; for(ll y=0;y<=cnt;y++) g[j+1][y]=min(g[j+1][y],g[j][x]+f[b[i][j]][x][y]); } } for(ll x=0;x<=cnt;x++){ flag|=(g[b[i].size()][x]<f[a[i]][s][x]); f[a[i]][s][x]=min(f[a[i]][s][x],g[b[i].size()][x]); } } return flag; } void SPFA(){ q.push(0);q.push(1);v[0]=v[1]=1; while(!q.empty()){ int x=q.front();q.pop();v[x]=0; for(int i=0;i<T[x].size();i++){ int y=T[x][i]; if(solve(y)&&!v[a[y]]) q.push(a[y]),v[a[y]]=1; } } return; } signed main() { scanf("%lld%lld%lld",&G,&n,&m); for(ll i=1,k;i<=n;i++){ scanf("%lld%lld",&a[i],&k); for(ll j=1,x;j<=k;j++){ scanf("%lld",&x),b[i].push_back(x); T[x].push_back(i); } } for(ll i=1,k;i<=m;i++){ scanf("%lld",&k); ins(k); } getfail();ll k=0; memset(f,0x3f,sizeof(f)); for(ll i=0;i<=cnt;i++){ if(ed[i])continue; if(!ed[ch[i][0]])f[0][i][ch[i][0]]=1; if(!ed[ch[i][1]])f[1][i][ch[i][1]]=1; } SPFA(); for(ll i=2;i<G;i++){ ll ans=inf; for(ll x=0;x<=cnt;x++) ans=min(ans,f[i][0][x]); if(ans>=inf)puts("YES"); else printf("NO %lld\n",ans); } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16404011.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(125)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-06-23 P4258-[WC2016]挑战NPC【带花树】
2021-06-23 P7099-[yLOI2020]灼【数学期望,结论】
2021-06-23 P3190-[HNOI2007]神奇游乐园【插头dp】
2021-06-23 P5056-[模板]插头dp
点击右上角即可分享
微信分享提示