RT,WA on #13。LOJ上94pts,WA on #19。本题讨论版里的hack数据基本都过了。思路是删去不能被取的点后tarjan找环,并对自环做了特殊处理。代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+5;
const int V=(3e4+5)*2;
int n,nV;
vector<int> to[V],e[V];
void addedge(int u,int v)
{
if(v==u){++nV;to[u].push_back(nV);to[nV].push_back(u);} // 解决自环:加一个辅助点
else to[u].push_back(v);
}
string s[N];
int tr[V][2],fail[V],tag[V];
int low[V],tI[V],sz[V],scc,timer;
bool vis[V];
void insert(const string& s,int ID)
{
int len=s.length(),u=0;
for(int i=0;i<len;++i)
{
int o=s[i]-'0';
if(!tr[u][o]) tr[u][o]=++nV;
u=tr[u][o];
}
tag[u]=ID;
}
void build()
{
// 模板:构建AC自动机
queue<int> q;
for(int i=0;i<2;++i) if(tr[0][i]) q.push(tr[0][i]);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=0;i<2;++i)
if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);
else tr[u][i]=tr[fail[u]][i];
}
// 如果某节点u满足fail[u]不能取,那么u也不能取
for(int u=1;u<=nV;++u) if(fail[u]!=u) e[fail[u]].push_back(u); // 反向边
for(int u=1;u<=nV;++u) if(tag[u]) q.push(u);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int v:e[u])
{
tag[v]=N;
q.push(v);
}
}
}
// 模板:tarjan找环
int st[V],c[V],top;
void dfs(int u)
{
low[u]=tI[u]=++timer;
vis[u]=true;
st[++top]=u;
for(int v:to[u])
{
if(!tI[v]){dfs(v);low[u]=min(tI[u],tI[v]);}
else if(vis[v]) low[u]=min(low[u],low[v]);
}
if(tI[u]==low[u])
{
++scc;
while(st[top]!=u){++sz[scc];vis[st[top--]]=false;}
++sz[scc];
--top; vis[u]=false;
}
}
// void print()
// {
// cout << "-----\n";
// for(int u=0;u<=nV;++u) cout << tag[u] << " \n"[u==nV];
// for(int u=0;u<=nV;++u)
// for(int i=0;i<2;++i) cout << u << " " << tr[u][i] << " " << i << "\n";
// cout << "------\n";
// }
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>s[i];
insert(s[i],i);
}
build();
// VV=nV防止addedge中新加的辅助点影响加边
for(int u=0,VV=nV;u<=VV;++u) if(!tag[u])
{
int v=tr[u][0];
if(!tag[v])
addedge(u,v);
v=tr[u][1];
if(!tag[v])
addedge(u,v);
}
dfs(0);
// cout << scc << "\n";
for(int i=1;i<=scc;++i)
if(sz[i]>1) cout << "TAK\n",exit(0);
cout << "NIE\n";
return 0;
}
谢谢!