P10551 [THUPC 2024 决赛] 连向未来 题解
简化版题意:求出一个矩阵,使得可以对这个矩阵划分成若干条链,每条链形如
首先我们发现这个状态只和上一列有关,因此对于同一列的每个位置,我们有下面几种讨论:
- 它的上一个位置已经匹配,对于当前位置没有要求。
- 它的上一个位置是
1 ,需要当前位置为2 连接。 - 它的上一个位置是
3 ,需要当前位置为2 连接。 - 它的上一个位置是
2 ,需要当前位置为1 连边。 - 它的上一个位置是
2 ,需要当前位置为3 连边。
一共
这就是 NFA(非确定性有限状态自动机),我们考虑转化为 DFA(确定性有限状态自动机)。
比较暴力的做法就是记录当前状态可能的匹配是哪些,也就是在上面
考虑最小化 DFA,一个最简单的做法就是删去从起点开始不可达的状态,我们惊奇的发现,这样的状态只有
具体的,枚举完当前列的可能的匹配子集
所有不同的
为了避免篇幅过长,这里就只放
namespace TYPE_3{
vector<pair<ll,ll> > op[1005];
ll ttt,i,j,val[1005],a[1005],b[1005],vis[1005],news[1005],used[1005],idd[1005],s[1005][1005],tot,id2[1005];
map<ll,ll> maps;
inline void output(){
if(news[1]==-1||news[2]==-1||news[3]==-1) return ;
op[b[1]*100+b[2]*10+b[3]].push_back(make_pair(a[1]*100+a[2]*10+a[3],news[1]*100+news[2]*10+news[3]));
}
inline void solve(){
vis[1] = vis[2] = vis[3] = 0;
for(ll i=1;i<=3;i++){
vis[i]=0;
if(a[i]==1) continue;
if(a[i]==2||a[i]==3){
if(b[i]!=2) return ;
if(a[i]==2) vis[i]=1;
else vis[i]=2;
}
if(a[i]==4){
if(b[i]!=1) return ;
vis[i]=3;
}
if(a[i]==5){
if(b[i]!=3) return ;
vis[i]=4;
}
}
if(vis[1]==1) news[1]=5;
else if(vis[1]==2) news[1]=4;
else if(vis[1]==3) news[1]=1;
else if(vis[1]==4) news[1]=1;
else if(b[1]==1) news[1]=2;
else if(b[1]==2) news[1]=-1;
else news[1]=3;
if(vis[2]==1) news[2]=5;
else if(vis[2]==2) news[2]=4;
else if(vis[2]==3) news[2]=1;
else if(vis[2]==4) news[2]=1;
else if(b[2]==1) news[2]=2;
else if(b[2]==2) news[2]=-1;
else news[2]=3;
if(vis[3]==1) news[3]=5;
else if(vis[3]==2) news[3]=4;
else if(vis[3]==3) news[3]=1;
else if(vis[3]==4) news[3]=1;
else if(b[3]==1) news[3]=2;
else if(b[3]==2) news[3]=-1;
else news[3]=3;
output();
if((!vis[1]||!vis[2])&&abs(b[1]-b[2])==1){
if(vis[3]==1) news[3]=5;
else if(vis[3]==2) news[3]=4;
else if(vis[3]==3) news[3]=1;
else if(vis[3]==4) news[3]=1;
else if(b[3]==1) news[3]=2;
else if(b[3]==2) news[3]=-1;
else news[3]=3;
if(!vis[1]&&!vis[2]){
if(b[1]==1&&b[2]==2) news[1]=1,news[2]=5;
if(b[1]==2&&b[2]==1) news[1]=5,news[2]=1;
if(b[1]==2&&b[2]==3) news[1]=4,news[2]=1;
if(b[1]==3&&b[2]==2) news[1]=1,news[2]=4;
output();
}
else if(!vis[1]){
news[1]=1,news[2]=1;
if(vis[2]==1&&b[1]==3) output();
if(vis[2]==2&&b[1]==1) output();
}
else if(!vis[2]){
news[1]=1,news[2]=1;
if(vis[1]==1&&b[2]==3) output();
if(vis[1]==2&&b[2]==1) output();
}
}
if((!vis[2]||!vis[3])&&abs(b[2]-b[3])==1){
if(vis[1]==1) news[1]=5;
else if(vis[1]==2) news[1]=4;
else if(vis[1]==3) news[1]=1;
else if(vis[1]==4) news[1]=1;
else if(b[1]==1) news[1]=2;
else if(b[1]==2) news[1]=-1;
else news[1]=3;
if(!vis[3]&&!vis[2]){
if(b[3]==1&&b[2]==2) news[3]=1,news[2]=5;
if(b[3]==2&&b[2]==1) news[3]=5,news[2]=1;
if(b[3]==2&&b[2]==3) news[3]=4,news[2]=1;
if(b[3]==3&&b[2]==2) news[3]=1,news[2]=4;
output();
}
else if(!vis[3]){
news[3]=1,news[2]=1;
if(vis[2]==1&&b[3]==3) output();
if(vis[2]==2&&b[3]==1) output();
}
else if(!vis[2]){
news[3]=1,news[2]=1;
if(vis[3]==1&&b[2]==3) output();
if(vis[3]==2&&b[2]==1) output();
}
}
if(!vis[1]&&!vis[2]&&!vis[3]){
if(abs(b[1]-b[2])==1&&abs(b[2]-b[3])==1&&abs(b[1]-b[3])==2){
news[1]=1,news[2]=1,news[3]=1;
output();
}
}
}
inline void dfs(ll x){
if(x>3){
for(ll i=1;i<=3;i++){
for(ll j=1;j<=3;j++){
for(ll k=1;k<=3;k++){
b[1]=i,b[2]=j,b[3]=k;
solve();
}
}
}
return ;
}
for(ll i=1;i<=5;i++) a[x]=i,dfs(x+1);
}
inline void dfs2(ll S){
if(maps[S]) return ;
maps[S]=++tot,id2[tot]=S;
for(ll i=1;i<=3;i++){
for(ll j=1;j<=3;j++){
for(ll k=1;k<=3;k++){
ll p = i*100+j*10+k,newS = 0;
for(ll l=0;l<op[p].size();l++){
if(!idd[op[p][l].first]) continue;
if(!idd[op[p][l].second]) idd[op[p][l].second]=++ttt;
if((S>>idd[op[p][l].first])&1) newS|=(1ll<<idd[op[p][l].second]);
}
dfs2(newS);
s[maps[S]][maps[newS]]++;
}
}
}
}
vector<ll> v(0);
int main(){
dfs(1);
idd[111]=++ttt;
dfs2(2);
for(i=1;i<=tot;i++) if((id2[i]>>1)&1) v.push_back(i);
return 0;
}
}