【BZOJ2938】【luoguP2444】病毒

description

二進制病毒審查委員會最近發現瞭如下的規律:某些確定的二進制串是病毒的代碼。如果某段代碼中不存在任何一段病毒代碼,那麼我們就稱這段代碼是安全的。現在委員會已經找出了所有的病毒代碼段,試問,是否存在一個無限長的安全的二進制代碼。

示例:

例如如果{011, 11, 00000}爲病毒代碼段,那麼一個可能的無限長安全代碼就是010101…。如果{01, 11, 000000}爲病毒代碼段,那麼就不存在一個無限長的安全代碼。

任務:

請寫一個程序:

1.在文本文件WIR.IN中讀入病毒代碼;

2.判斷是否存在一個無限長的安全代碼;

3.將結果輸出到文件WIR.OUT中。


analysis

  • 對所有模式串建ACAC自動機,然後考慮可行的安全代碼在ACAC自動機上的匹配

  • 安全代碼若無限長,則必然在ACAC自動機上無限匹配、且不會匹配到失敗節點

  • 注意一個節點的failfail是失敗節點,該節點也是,因爲failfail的字符串是該點字符串的後綴

  • 然後在自動機上dfsdfs找出一個環,節點經過兩次則有解


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define MAXN 100005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)

using namespace std;

ll trie[MAXN][2],fail[MAXN],vis[MAXN];
bool bz[MAXN],flag[MAXN];
char s[30005];
ll n,tot,root;
queue<ll>q;

inline ll newnode(){++tot,trie[tot][0]=trie[tot][1]=-1;return tot;}
inline void init(){tot=0,root=newnode();}
inline void insert(char s[])
{
	ll len=strlen(s),now=root;
	fo(i,0,len-1)
	{
		if (trie[now][s[i]-'0']==-1)trie[now][s[i]-'0']=newnode();
		now=trie[now][s[i]-'0'];
	}
	flag[now]=1;
}
inline void buildfail()
{
	q.push(root),fail[root]=root;
	while (!q.empty())
	{
		ll now=q.front();q.pop();
		fo(i,0,1)if (trie[now][i]==-1)trie[now][i]=(now==root?root:trie[fail[now]][i]);
		else flag[trie[now][i]]|=flag[trie[fail[now]][i]],fail[trie[now][i]]=(now==root?root:trie[fail[now]][i]),q.push(trie[now][i]);
	}
}
inline bool dfs(ll x)
{
	if (vis[x]==1)return 1;
	if (vis[x]==-1)return 0;vis[x]=1;
	fo(i,0,1)if (!flag[trie[x][i]]){if (dfs(trie[x][i]))return 1;}
	vis[x]=-1;return 0;
}
int main()
{
	//freopen("P2444.in","r",stdin);
	scanf("%lld",&n),init();
	fo(i,1,n)scanf("%s",&s),insert(s);
	buildfail(),printf(dfs(root)?"TAK\n":"NIE\n");
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章