【题目描述】:
【题目解法】:
首先我们枚举一对自动机(i,j),然后判断j是否为i的升级
我们可以用bfs判定,我们用(x,y)表示在i自动机的第x个节点和j自动机的第y个节点,如果到达某个状态(x,y)使得x是输出节点而y不是输出节点,那么说明存在一个字符串x可以输出y不能输出,因此j就不是i的升级,反之j就是i的升级。
然后状态只有O(N^2),因此一次bfs复杂度就是O(N^2)
如果j是i的升级我们连边i->j
然后我们得到一个有向图,我们需要求出最长路
我们先同tarjan求出SCC,对于同一个联通分量里面的点那么可以全部选取
因此我们用拓扑dp求出最长路即可
复杂度O(N^4)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=101;
const int M=8005;
inline long long getint()
{
long long x=0; char c=getchar(); bool flag=false;
while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
if (c=='-') flag=true,c=getchar();
while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
if (flag) return -x; else return x;
}
struct Auto
{
int n,m,trans[N][2]; bool v[N];
void init()
{
n=getint(); m=getint();
for (int i=1; i<=m; i++) v[getint()+1]=true;
for (int i=1; i<=n; i++) trans[i][0]=getint()+1,trans[i][1]=getint()+1;
}
} a[N];
int n,size[N];
void init()
{
n=getint();
for (int i=1; i<=n; i++) a[i].init();
}
namespace SCC
{
struct edge {int x,next;} b[M];
int tot,a[N],ans,into[N],q[N],f[N];
void addedge(int x,int y)
{
++tot;
b[tot].x=y;
b[tot].next=a[x];
a[x]=tot;
into[y]++;
}
void solve()
{
int head=0,tail=0;
for (int i=1; i<=n; i++) if (into[i]==0) q[++tail]=i,f[i]=size[i];
while (head<tail)
{
int k=q[++head]; ans=max(ans,f[k]);
for (int p=a[k];p;p=b[p].next)
{
int pp=b[p].x; f[pp]=max(f[pp],f[k]+size[pp]);
--into[pp]; if (into[pp]==0) q[++tail]=pp;
}
}
printf("%d\n",ans);
}
}
namespace Tarjan
{
struct edge {int x,next;} b[M]; int v[N];
int tot,a[N],dfn[N],cnt,low[N],belong[N],top,stack[N],time;
void addedge(int x,int y)
{
++tot;
b[tot].x=y;
b[tot].next=a[x];
a[x]=tot;
}
void dfs(int x)
{
++time; low[x]=dfn[x]=time; stack[++top]=x; v[x]=1;
for (int p=a[x];p;p=b[p].next)
{
int pp=b[p].x;
if (v[pp]==0) dfs(pp);
if (v[pp]==1) low[x]=min(low[x],low[pp]);
}
if (low[x]!=dfn[x]) return; ++cnt;
while (stack[top+1]!=x)
{
v[stack[top]]=2;
belong[stack[top]]=cnt; size[cnt]++;
top--;
}
}
void solve()
{
for (int i=1; i<=n; i++) if (v[i]==0) dfs(i);
for (int i=1; i<=n; i++)
for (int p=a[i];p;p=b[p].next)
if (belong[i]!=belong[b[p].x]) SCC::addedge(belong[i],belong[b[p].x]);
}
}
namespace JudgeLevel
{
struct node {int x,y;} q[M];
int cnt,id[N][N];
bool bfs(int i,int j)
{
++cnt; int head=0,tail=1;
q[1].x=1; q[1].y=1; id[1][1]=cnt;
while (head<tail)
{
++head; int x=q[head].x,y=q[head].y;
if ((a[i].v[x])&&(!a[j].v[y])) return false;
for (int k=0; k<=1; k++)
{
int nx=a[i].trans[x][k],ny=a[j].trans[y][k];
if (id[nx][ny]==cnt) continue; id[nx][ny]=cnt;
q[++tail].x=nx; q[tail].y=ny;
}
}
return true;
}
void solve()
{
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
if ((i!=j)&&(bfs(i,j))) Tarjan::addedge(i,j);
}
}
int main()
{
init();
JudgeLevel::solve();
Tarjan::solve();
SCC::solve();
return 0;
}