#2210. Hamilton Path 题解
题目链接:#2210. Hamilton Path
首先我们发现,固定第一个节点后,整个排列 $ p $ 唯一,因为如果有一步同时出现了两个没有走过的节点,那么假设先走了任意一个,再之后走到另一个是就会不满足限制。那么我们可以考虑一开始将所有点视为长度为 $ 1 $ 的链,然后每次合并两条链。可以合并的条件是某一条链只有一个链以外的后继。最终在若干次合并后肯定会出现链无法再合并的情况,如果最后剩两条链,那么显然要从一条只有一个后继节点的链头开始走(因为如果从链中间开始走,则他的前驱没有任何可以走的后继,必须成为终点;而因为链尾没有任何链头作为后继,则链尾必然跳到另一条链的链中间,同理也要成为终点,矛盾。同理合法起点也不超过两个,否则同样会产生前向边),暴力判每个起点是否合法即可。
如果最终只剩下一条链,我们定义 $ pre_u $ 为 $ u $ 走一条回溯边能走到编号最小的节点。首先对于起点 $ p_s $,肯定有答案排列的一段前缀一定是原排列以 $ p_s $ 开头一直到 $ p_n $ 的这一段后缀,正确性显然。然后设 $ pre_{p_n}=p_x $ ,如果 $ p_n $ 没有任何后继,显然只有原排列一个解,否则下一步一定走 $ p_x $,因此 $ x<s $ 否则下一步没得走。
如果存在一个 $ i\le j<n $ 满足 $ pre_{p_j}<i $,那么如果 $ s\le j $,显然在走到 $ j $ 的时候有两个后继,矛盾,如果 $ s>j+1 $,走到 $ j $ 的时候也会存在两个后继同样非法,因此如果存在这样的 $ j $, 起点 $ s $ 必然为 $ j+1 $。如果不存在这样的 $ j $,那么从 $ p_n $ 跳到 $ p_i $ 后,一直走到 $ p_{s-1} $,此时没有任何后继,因此没有其他的解。
如果 $ pre_{p_n}=1 $,那么显然在不考虑其他回溯边的情况下原排列的任意循环移位都符合条件。现在考虑一条回溯边 $ p_r \to p_l $,如果在循环移位后先访问 $ r $ 那么显然非法,因此相当于禁止 $ s\in (l, r] $。
对于哈希值,显然对于除了最后一种情况,其他情况答案只有 $ O(1) $ 个,可以直接计算,对于循环移位可以用类似字符串哈希的方法计算。
代码:
#include<bits/stdc++.h>
#define time(null) chrono::steady_clock::now().time_since_epoch().count()
#define int long long
#define uint unsigned long long
#define debug() cout<<"come here\n"
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define pb push_back
#define Code return
#define by 0
#define MCYYDS ;
using namespace std;
int qpow(int a,int b,int p=INF){int ret=1;while(b){if(b&1)ret=(ret*a)%p;a=(a*a)%p;b>>=1;}return ret;}
inline int read(){int ret=0,f=1;char ch=getchar();while(ch<'0'||ch>'9')f=(ch=='-'?-1:f),ch=getchar();while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+(ch^48),ch=getchar();return ret*f;}
inline void write(int x){if(x<0){putchar('-');write(-x);return ;}if(x>9)write(x/10);putchar((char)(x%10+48));}
inline void writech(int x,char ch){write(x);putchar(ch);}
const int mod=1e9+7;
int n,m;
vector<vector<int> > e;
vector<set<int> > g;
vector<int> fa,sz,head,tail,nxt;
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int merge(int u,int v)
{
u=find(u),v=find(v);
int h=head[u],t=tail[v],tu=tail[u],su=sz[u],sv=sz[v];
if(su<=g[t].size())
{
for(int i=head[u];i;i=nxt[i])
{
g[t].erase(i);
}
}
else
{
for(auto it=g[t].begin();it!=g[t].end();)
{
if(find(*it)==u)it=g[t].erase(it);
else it++;
}
}
nxt[tu]=head[v];
int ret;
if(su<sv)fa[u]=ret=v;
else fa[v]=ret=u;
sz[ret]=su+sv;
head[ret]=h;
tail[ret]=t;
return ret;
}
vector<int> check(int st)
{
vector<int> vis(n+1,0);
vector<int> p;
int u=st;
vis[u]=1;
p.pb(u);
while(p.size()<n)
{
int v=0;
for(auto x:e[u])
{
if(!vis[x])
{
if(v)return vector<int>();
v=x;
}
}
if(!v)return vector<int>();
u=v;
vis[u]=1;
p.pb(u);
}
return p;
}
int gethsh(vector<int> &p)
{
int ret=0;
for(auto x:p)
{
ret=(ret*10+x)%mod;
}
return ret;
}
queue<int> q;
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
int T=read();
while(T--)
{
n=read(),m=read();
e.assign(n+1,vector<int>());
g.resize(n+1);
fa.assign(n+1,0);
sz.assign(n+1,1);
head.assign(n+1,0);
tail.assign(n+1,0);
nxt.assign(n+1,0);
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
e[u].pb(v);
}
for(int i=1;i<=n;i++)
{
sort(e[i].begin(),e[i].end());
e[i].erase(unique(e[i].begin(),e[i].end()),e[i].end());
}
while(q.size())q.pop();
for(int i=1;i<=n;i++)
{
g[i].clear();
for(auto x:e[i])
{
g[i].insert(x);
}
fa[i]=head[i]=tail[i]=i;
q.push(i);
}
while(q.size())
{
int id=find(q.front());
q.pop();
int u=tail[id];
if(g[u].size()!=1)continue;
int v=(*g[u].begin()),tv=find(v);
if(tv==id||head[tv]!=v)continue;
q.push(merge(id,tv));
}
vector<int> root;
for(int i=1;i<=n;i++)
{
if(find(i)==i)root.pb(i);
}
vector<pii > ans;
if(root.size()>1)
{
vector<int> ok;
for(auto x:root)
{
if(g[tail[x]].size()==1)ok.pb(head[x]);
}
if(ok.size()>2)
{
puts("0");
continue;
}
for(auto st:ok)
{
vector<int> p=check(st);
if(p.size())ans.pb({st,gethsh(p)});
}
sort(ans.begin(),ans.end());
writech(ans.size(),'\n');
for(int i=0;i<ans.size();i++)
{
writech(ans[i].second,' ');
}
puts("");
}
else
{
int r=root[0],u=head[r];
vector<int> p,pos(n+1),pre(n,n);
while(u)
{
p.pb(u);
u=nxt[u];
}
for(int i=0;i<n;i++)
{
pos[p[i]]=i;
}
for(int i=0;i<n;i++)
{
for(auto v:e[p[i]])
{
if(pos[v]<i)pre[i]=min(pre[i],pos[v]);
}
}
int hsh=gethsh(p);
if(pre[n-1]==0)
{
vector<int> d(n+1,0);
for(int i=0;i<n;i++)
{
for(auto v:e[p[i]])
{
if(pos[v]>=i||(i==n-1&&pos[v]==0))continue;
d[pos[v]+1]++;
d[i+1]--;
}
}
int sum=0;
for(int i=0;i<n;i++)
{
sum+=d[i];
if(sum==0)ans.pb({p[i],hsh});
hsh=(hsh-p[i]*qpow(10,n-1,mod)%mod+mod)%mod;
hsh=(hsh*10+p[i])%mod;
}
sort(ans.begin(),ans.end());
writech(ans.size(),'\n');
for(int i=0;i<ans.size();i++)
{
writech(ans[i].second,' ');
}
puts("");
}
else
{
ans.pb({p[0],hsh});
if(pre[n-1]<n)
{
int st=0;
for(int j=pre[n-1];j<n-1;j++)
{
if(pre[j]<pre[n-1])
{
st=p[j+1];
break;
}
}
if(st)
{
vector<int> q=check(st);
if(q.size())ans.pb({st,gethsh(q)});
}
}
sort(ans.begin(),ans.end());
writech(ans.size(),'\n');
for(int i=0;i<ans.size();i++)
{
writech(ans[i].second,' ');
}
puts("");
}
}
}
Code by MCYYDS
}

浙公网安备 33010602011771号