zoukankan      html  css  js  c++  java
  • BZOJ2938 [Poi2000]病毒 和 BZOJ5261 Rhyme

    [Poi2000]病毒

    二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

    示例:例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。

    任务:请写一个程序:

    1. 读入病毒代码;
    2. 判断是否存在一个无限长的安全代码;
    3. 将结果输出

    给出若干个 01 串,问是否存在一个无限长的 01 串,满足所有给出的串都不是它的子串.

    jklover的题解

    将给出的串插入到 AC 自动机里,那么若存在一个环,环上的节点及它们沿 fail 指针向上跳都不经过单词末节点,则符合要求.

    插入的时候将权值一起合并,最后做一次 dfs 即可.

    时间复杂度:线性。

    co int N=3e4+1,S=2;
    namespace AC
    {
    	int idx;
    	int ch[N][S],fail[N],val[N];
    	
    	void ins(char*s,int len)
    	{
    		int u=0;
    		for(int i=0;i<len;++i)
    		{
    			int k=s[i]-'0';
    			if(!ch[u][k])
    				ch[u][k]=++idx;
    			u=ch[u][k];
    		}
    		val[u]=1;
    	}
    	
    	void getfail()
    	{
    		std::queue<int>Q;
    		for(int i=0;i<S;++i)
    			if(ch[0][i])
    				Q.push(ch[0][i]);
    		while(Q.size())
    		{
    			int u=Q.front();Q.pop();
    			for(int i=0;i<S;++i)
    			{
    				if(ch[u][i])
    				{
    					fail[ch[u][i]]=ch[fail[u]][i];
    					val[ch[u][i]]|=val[ch[fail[u]][i]];
    					Q.push(ch[u][i]);
    				}
    				else
    					ch[u][i]=ch[fail[u]][i];
    			}
    		}
    	}
    	
    	int vis[N],inc[N];
    	
    	int dfs(int u)
    	{
    		inc[u]=1;
    		for(int i=0;i<S;++i)
    		{
    			int v=ch[u][i];
    			if(inc[v])
    				return 1;
    			if(vis[v]||val[v])
    				continue;
    			vis[v]=1;
    			if(dfs(v))
    				return 1;
    		}
    		inc[u]=0;
    		return 0;
    	}
    	
    	void solve()
    	{
    		puts(dfs(0)?"TAK":"NIE");
    	}
    }
    int n;
    char buf[N];
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	read(n);
    	for(int i=1;i<=n;++i)
    	{
    		scanf("%s",buf);
    		AC::ins(buf,strlen(buf));
    	}
    	AC::getfail();
    	AC::solve();
    	return 0;
    }
    

    Rhyme

    由于多次交换邮票没有满足所有人的需求,小Z被赶出了集邮部。无处可去的小Z决定加入音乐部,为了让音乐部的人注意到自己的才华,小Z想写一首曲子。为了让自己的曲子更好听,小Z找到了一些好听曲子作为模板。曲谱可以表示成只包含小写字母的字符串,小Z希望自己最终的曲谱中任意一个长度为K的子串都是一个模板的子串。现在小Z想知道自己的曲谱最长可以是多长,如果可以无限长的话请输出INF。

    每组数据字符串总长不超过100000,1≤K≤100000。每个测试点数据不超过10组。

    dummyummy的题解

    可以先看一下这道题 [POI2000]病毒,虽然是个AC自动机,不过思路很像。

    对于这道题,我们只需要把广义SAM建出来,然后在那些只经过maxlen⩾k的结点的路径中选一个最长的就行了。最后一步可以用拓扑排序来完成。

    拓扑建边时可以直接向fail连边,而不是把儿子补全(像AC自动机那样ch[u][c]=ch[fail[u]][c]),这样能降低复杂度。

    最后如果出现环,就输出INF,否则求最长路径,注意特判所有结点的maxlen都小于k的情况,题目最下方有说明。

    时间复杂度(O(sum |s|))

    typedef pair<int,int> pii;
    
    co int N=2e5+3;
    int n,k;
    char str[N];
    int tot;
    int ch[N][26],fa[N],len[N];
    vector<pii> g[N];
    int ind[N],dis[N];
    void clear(){
    	for(int i=1;i<=tot+2;++i){
    		memset(ch[i],0,sizeof ch[i]);
    		g[i].clear(),ind[i]=dis[i]=0;
    	}
    	tot=1;
    }
    int extend(int p,int c){
    	int last;
    	if(ch[p][c]){
    		int q=ch[p][c];
    		if(len[q]==len[p]+1) last=q;
    		else{
    			int clone=last=++tot;
    			memcpy(ch[clone],ch[q],sizeof ch[q]);
    			fa[clone]=fa[q],len[clone]=len[p]+1;
    			fa[q]=clone;
    			for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
    		}
    	}
    	else{
    		int cur=last=++tot;
    		len[cur]=len[p]+1;
    		for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
    		if(!p) fa[cur]=1;
    		else{
    			int q=ch[p][c];
    			if(len[q]==len[p]+1) fa[cur]=q;
    			else{
    				int clone=++tot;
    				memcpy(ch[clone],ch[q],sizeof ch[q]);
    				fa[clone]=fa[q],len[clone]=len[p]+1;
    				fa[cur]=fa[q]=clone;
    				for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
    			}
    		}
    	}
    	return last;
    }
    void Rhyme(){
    	clear();
    	for(int i=1;i<=n;++i){
    		scanf("%s",str+1);
    		int len=strlen(str+1),last=1;
    		for(int j=1;j<=len;++j) last=extend(last,str[j]-'a');
    	}
    	int s=tot+1,t=tot+2;
    	for(int i=1;i<=tot;++i){
    		if(len[i]==k-1){
    			for(int j=0;j<26;++j)if(ch[i][j]) g[i].push_back(pii(ch[i][j],1)),++ind[ch[i][j]];
    			g[s].push_back(pii(i,len[i])),++ind[i];
    		}
    		else if(len[i]>=k){
    			for(int j=0;j<26;++j)if(ch[i][j]) g[i].push_back(pii(ch[i][j],1)),++ind[ch[i][j]];
    			if(fa[i]&&len[fa[i]]>=k-1) g[i].push_back(pii(fa[i],0)),++ind[fa[i]];
    			g[i].push_back(pii(t,0)),++ind[t];
    			g[s].push_back(pii(i,len[i])),++ind[i];
    		}
    	}
    	if(!ind[t]) return printf("%d
    ",k-1),void();
    	int ans=0;
    	queue<int> q;q.push(s);
    	for(int u;!q.empty();q.pop()){
    		u=q.front(),ans=max(ans,dis[u]);
    		for(int i=0,v;i<g[u].size();++i){
    			v=g[u][i].first,dis[v]=max(dis[v],dis[u]+g[u][i].second);
    			if(!--ind[v]) q.push(v);
    		}
    	}
    	for(int i=1;i<=tot;++i)if(ind[i]) return puts("INF"),void();
    	printf("%d
    ",ans);
    }
    int main(){
    	while(~scanf("%d %d",&n,&k)) Rhyme();
    	return 0;
    }
    
  • 相关阅读:
    pat00-自测5. Shuffling Machine (20)
    Spiral Matrix
    Search in Rotated Sorted Array II
    Search in Rotated Sorted Array
    Best Time to Buy and Sell Stock II
    4Sum
    3Sum Closest
    3Sum
    MySQL存储过程、函数和游标
    Word Ladder
  • 原文地址:https://www.cnblogs.com/autoint/p/10899121.html
Copyright © 2011-2022 走看看