用欧拉路径判断图同构推出reverse合法性:1116T4

http://cplusoj.com/d/senior/p/SS231116D

假设我们要把 a a a 变成 b b b,我们在 a i a_i ai a i + 1 a_{i+1} ai+1 之间连边, b b b 同理,则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。

必要性显然,因为无论如何reverse都不会改变图的形态。我们现在要证明的是图的任意欧拉路径都可以通过reverse构造出来。

考虑第一个 a i ≠ b i a_i\neq b_i ai=bi 的位置 i i i,设 x = b i , y = b i − 1 = a i − 1 x=b_i,y=b_{i-1}=a_{i-1} x=bi,y=bi1=ai1。在图同构是必然存在一个 a k = x a_k=x ak=x,且 a k − 1 a_{k-1} ak1 a k + 1 a_{k+1} ak+1 其中一个等于 y y y。(注意 A , B A,B A,B 同构)

如果 a k + 1 = y a_{k+1}=y ak+1=y,我们直接reverse即可。如果 a k − 1 = y a_{k-1}=y ak1=y,我们只需要考虑 ( x , y ) (x,y) (x,y) 这条边在 A A A 中是不是桥就行。因为在 B B B 中一定不是桥(注意到 y y y 必然出现两次)

因为如果在 A A A 中是桥, B B B 中不是,说明 A , B A,B A,B 不同构,和我们的前提冲突。

如果在 A A A 中不是桥,说明对于这条边来说 A , B A,B A,B 同构,说明一定存在 i ≤ l ≤ k − 1 , r > k + 1 i\le l \le k-1,r>k+1 ilk1,r>k+1 满足 a l = a r a_l=a_r al=ar。我们直接按 [ l , r ] [l,r] [l,r] reverse即可。因此一定可以构造

#include 
#include 
#include 
#include 

using namespace std;

struct xorShift128Plus {
	unsigned long long k1, k2;
	unsigned long long gen() {
		register unsigned long long k3 = k1, k4 = k2;
		k1 = k4;
		k3 ^= k3 << 23;
		k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
		return k2 + k4;
	}
	int gen(int w) {
		return gen()%w;
	}
}rnd;

const int S=5000005;
#define pb push_back
#define fi first
#define se second

int n, a[S], t[S], k, i, tot;
bool b[S]; 
int ans[S];
vector<pair<int, int> >G[S]; 

void dfs(int x) {
	for(; t[x]<G[x].size(); ){
		auto p=G[x][t[x]]; ++t[x]; 
		if(b[p.se]) continue; 
		int y=p.fi; b[p.se]=1; 
		dfs(y); 
	}
	ans[++tot]=x; 
}

void cun(int x, int y) {
	G[x].pb({y, ++k}); G[y].pb({x, k}); 
}

int main()
{
	freopen("life.in","r",stdin);
	freopen("life.out","w",stdout);
		#ifdef LOCAL
	  freopen("in.txt", "r", stdin);
	  freopen("out.txt", "w", stdout);
	#endif
	int t;
	scanf("%d%d",&n,&t);
	if(t==0) for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	else
	{
		int ra;
		scanf("%d%llu%llu",&ra,&rnd.k1,&rnd.k2);
		for(int i=1;i<=n;i++) a[i]=rnd.gen(ra)+1;
	}
	
//	cun(n+1, a[1]); cun(n+2, a[n]); 
	for(i=1; i<n; ++i) cun(a[i], a[i+1]); 
	for(i=1; i<=n+2; ++i) {
		sort(G[i].begin(), G[i].end()); 
//		reverse(G[i].begin(), G[i].end()); 
	}
	dfs(a[1]); reverse(ans+1, ans+n+1); 
	
	/*
		code here
	*/
	if(t==0)
	{
		for(int i=1;i<=n;i++) printf("%d ",ans[i]);
		printf("\n");
	}
	else
	{
		int bse=1919839,p=1000000007;
		int mul=1,res=0;
		for(int i=1;i<=n;i++,mul=1ll*mul*bse%p) res=(res+1ll*ans[i]*mul%p)%p;
		printf("%d\n",res);
	}
	return 0;
}

你可能感兴趣的:(欧拉路径,构造)