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}\),则原式变为:
于是图中期望只剩 \(\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;
}

浙公网安备 33010602011771号