92pts 求助
查看原帖
92pts 求助
270791
WanderingTrader楼主2024/4/22 22:22

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;
}

谢谢!

2024/4/22 22:22
加载中...