LibreOJ 3077 绝目编诗

题目传送门

首先注意到如果 \(m\) 太大,这个图中会有超过 \(n\) 个环,那么就一定有两个环长度相同了。

事实上这个界的级别是 \(O(n)\) 的,也就是说现在 \(n,m\) 同阶了。

考虑对于每一个点进行搜索,找出包含这个点的环。而如果在整个搜索过程中,一个包含 \(k\) 个点的环出现了超过 \(2\times k\) 次,那么就有两个长度相同的环。

这样我们获得了一个指数级别的做法,考虑怎么优化到多项式时间复杂度。

其实,我们可以在搜索到每个点时,再搜索一次,如果这个点不走已经走过的点回不到出发点的话,直接中断搜索。这个东西的复杂度是 \(O(n^4)\) 的,能获得 \(80\) 分。

不难发现,该图环最多的时候只有长度为 \(3\sim n\) 的环,那么如果我们在图中随机删边,令每条边有 \(\dfrac {1}{\sqrt n}\) 的概率被删除,那么期望会删除 \(O(\sqrt n)\) 条边。

对于一个长度为 \(len\) 的环,这个环能留下来的概率为 \((1-\dfrac{1}{\sqrt n})^{len}\),即图中剩余环的数量的期望为\(\displaystyle\sum_{i=3}^{n}(1-\dfrac{1}{\sqrt n})^{i}\)

\(q=1-\dfrac{1}{\sqrt n}\),则原式变为:

\[\displaystyle\sum_{i=3}^{n}(1-\dfrac{1}{\sqrt n})^{i}=\dfrac{q^3-q^{n-1}}{1-q}<\dfrac{1}{1-q}=\sqrt n \]

于是图中期望只剩 \(\sqrt n\) 条边,也就是说我们再删掉 \(\sqrt n\) 条边即可把图中的环全部删掉。

即当 \(m>n+2\times \sqrt n\) 时,一定存在两个简单环长度相同。

于是我们搞出一棵生成树,把所有非树边的点搞出来建立虚树,然后再把这些非树边加到虚树上,这样原图中所有环仍然存在,但是此时点数和边数都是 \(O(\sqrt n)\) 量级的,也就是说我们跑原来 \(O(n^4)\) 的算法实际只有 \(O((\sqrt n)^4)=O(n^2)\) 的时间复杂度。

AC code:

#include<bits/stdc++.h>
#define int long long
#define N 10005
#define K 15
#define pii pair<int,int>
#define x first
#define y second
#define mod 1000000007
#define inf 2e18
using namespace std;
int T=1,n,m;
struct nt{
	struct node{
		int a,b,c;
	};
	vector<node>e[N];
	int cnt[N],tot,ao=-1,rt,s[N];
	bool st[N];
	void add(int a,int b,int c){
		ao++;
		e[a].push_back({b,c,ao/2});
	}
	bool check(int u,int las){
		s[u]=tot;
		for(auto it:e[u]){
			int j=it.a,id=it.c;
			if(id==las)continue;
			if(j==rt)return 1;
			if(s[j]==tot||st[j])continue;
			if(check(j,id))return 1;
		}
		return 0;
	}
	void dfs(int u,int las,int len,int sum){
		tot++;
		if(!check(u,las))return;
		st[u]=1;
		for(auto it:e[u]){
			int j=it.a,w=it.b,id=it.c;
			if(id==las)continue;
			if(st[j]){
				if(j!=rt)continue;
				int cur=sum+w;
				cnt[cur]++;
				if(cnt[cur]>len*2){
					cout<<"Yes\n";
					exit(0);
				}
			}
			else dfs(j,id,len+1,sum+w);
		}
		st[u]=0;
	}
	void work(){
		for(int i=1;i<=n;i++){
			rt=i;
			dfs(i,0,1,0);
		}
		cout<<"No\n";
	}
}nt;
struct vt{
	vector<int>e[N];
	int dfn[N],dep[N],f[N][K],tot;
	int stk[N],s[N],top;
	void add(int a,int b){
		e[a].push_back(b);
	}
	void dfs(int u,int fa){
		dfn[u]=++tot;
		dep[u]=dep[fa]+1;
		f[u][0]=fa;
		for(int j=1;j<K;j++){
			f[u][j]=f[f[u][j-1]][j-1];
		}
		for(auto j:e[u]){
			if(j==fa)continue;
			if(dfn[j]){
				if(dfn[j]>dfn[u]){
					stk[++top]=u;
					stk[++top]=j;
					nt.add(u,j,1);
					nt.add(j,u,1);
				}
			}
			else dfs(j,u);
		}
	}
	int get_lca(int u,int v){
		if(dep[u]<dep[v])swap(u,v);
		for(int i=K-1;~i;i--){
			if(dep[f[u][i]]>=dep[v]){
				u=f[u][i];
			}
		}
		if(u==v)return u;
		for(int i=K-1;~i;i--){
			if(f[u][i]!=f[v][i]){
				u=f[u][i];
				v=f[v][i];
			}
		}
		return f[u][0];
	}
	int get_dist(int a,int b){
		int p=get_lca(a,b);
		return dep[a]+dep[b]-dep[p]*2;
	}
	void build(){
		sort(stk+1,stk+top+1,[&](int x,int y){
			return dfn[x]<dfn[y];
		});
		int m=unique(stk+1,stk+top+1)-stk-1;
		top=1;
		s[top]=stk[1];
		for(int i=2;i<=m;i++){
			int u=stk[i],l=get_lca(s[top],u);
			while(top>1&&dep[s[top-1]]>=dep[l]){
				nt.add(s[top-1],s[top],get_dist(s[top-1],s[top]));
				nt.add(s[top],s[top-1],get_dist(s[top-1],s[top]));
				top--;
			}
			if(s[top]!=l){
				nt.add(l,s[top],get_dist(l,s[top]));
				nt.add(s[top],l,get_dist(l,s[top]));
				s[top]=l;
			}
			s[++top]=u;
		}
		while(top>1){
			nt.add(s[top-1],s[top],get_dist(s[top-1],s[top]));
			nt.add(s[top],s[top-1],get_dist(s[top-1],s[top]));
			top--;
		}
	}
}vt;
void solve(int cs){
	cin>>n>>m;
	if(m>n+2*sqrt(n)){
		cout<<"Yes\n";
		return;
	}
	for(int i=1;i<=m;i++){
		int a,b;
		cin>>a>>b;
		vt.add(a,b);vt.add(b,a);
	}
	for(int i=1;i<=n;i++){
		if(!vt.dfn[i]){
			vt.dfs(i,0);
			vt.build();
		}
	}
	nt.work();
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//	cin>>T;
//	init();
	for(int cs=1;cs<=T;cs++){
		solve(cs);
	}
	return 0;
}
posted @ 2025-04-01 17:58  zxh923  阅读(33)  评论(0)    收藏  举报