Loj#3077-「2019 集训队互测 Day 4」绝目编诗【结论,虚树,鸽笼原理】
正題
題目鏈接:https://loj.ac/p/3077
題目大意
給出nnn個點mmm條邊的一張簡單無向圖,求是否存在兩個長度相等的簡單環(huán)。
1≤n≤104,1≤m≤1061\leq n\leq 10^4,1\leq m\leq 10^61≤n≤104,1≤m≤106
解題思路
先考慮一個暴力的做法,我們暴力搜索圖上的所有環(huán),記cic_ici?表示長度為iii的環(huán)的個數(shù)。
那么注意到一個長度為xxx的環(huán),我們會重復統(tǒng)計2x2x2x次(一輪和翻轉后的一輪),所以如果cx>2xc_x>2xcx?>2x那么就可以輸出YesYesYes了。
根據(jù)鴿籠原理,我們能注意到圖上的環(huán)的總數(shù)不能超過n?2n-2n?2(長度為3~n3\sim n3~n的各一個),否則答案一定是YesYesYes。然后考慮在一棵樹上,我們每加入一條邊后至少增加一個環(huán),所以如果m≥2n?3m\geq 2n-3m≥2n?3的話答案一定是YesYesYes,這樣我們就成功讓mmm就和nnn同級了。
然后考慮如果我們走的每一步都能保證往后是能搜出至少一個環(huán)的話,那么一個環(huán)最多被統(tǒng)計2x2x2x次,也就是要搜2x22x^22x2個點,那么如果答案是NoNoNo我們就最多只需要搜∑i=1n2i2\sum_{i=1}^n2i^2∑i=1n?2i2也就是O(n3)O(n^3)O(n3)級別次。
那么如何保證我們走的每個點一定能搜出環(huán),很簡單,假設我們的環(huán)從sss出發(fā),我們走到一個點是時暴力O(n)O(n)O(n)地判斷它是否能不經(jīng)過目前重復的走到sss,如果能那么它搜下去至少會有一個新的環(huán)。
這樣我們就做到O(n4)O(n^4)O(n4)的復雜度了。
然后是一個神仙優(yōu)化
我們假設我們在圖上刪除n\sqrt nn?條邊,那么每條邊被刪除的概率就是1n\frac{1}{\sqrt n}n?1?,假設圖恰好長度為3~n3\sim n3~n的環(huán)各有一個,那么一個長度為xxx的環(huán)沒被刪除的概率就是(1?1n)x(1-\frac{1}{\sqrt n})^x(1?n?1?)x,同理那最后圖上剩下的環(huán)的期望個數(shù)就是
∑i=3n(1?1n)i<11?(1?1n)=n\sum_{i=3}^n\left(1-\frac{1}{\sqrt n}\right)^i<\frac{1}{1-\left(1-\frac{1}{\sqrt n}\right)}=\sqrt ni=3∑n?(1?n?1?)i<1?(1?n?1?)1?=n?
所以刪除n\sqrt nn?條邊之后圖上期望剩下n\sqrt{n}n?個環(huán),因為是隨機刪的,所以如果按照最優(yōu)去刪除的話肯定存在一種方案使得圖上剩下不超過n\sqrt nn?個環(huán)。
然后我們指定刪一條邊肯定能刪掉一個環(huán),所以我們只需要刪除2n2\sqrt n2n?條邊就可以使得圖上不存在任何一個環(huán),換句話說我只需要刪除2n2\sqrt n2n?條邊就可以讓這張圖的邊數(shù)不超過n?1n-1n?1,所以這張圖的邊數(shù)不超過n?1+2nn-1+2\sqrt nn?1+2n?。
所以再換句話說,我們就得到了最重要的結論,如果圖的邊數(shù)大于等于n+2nn+2\sqrt nn+2n?那么答案肯定是YesYesYes。
所以我們只需要考慮怎么處理n+2nn+2\sqrt nn+2n?的情況,我們先找出一棵生成樹,然后對于所有的非樹邊的端點建出一棵虛樹,然后連接上非樹邊,這樣我們就得到一張邊數(shù)和點數(shù)都是n\sqrt nn?級別的圖。
不難發(fā)現(xiàn)我們上面那種情況也是能處理帶權圖的(需要注意的是一個長度為xxx的環(huán)出現(xiàn)的次數(shù)不是2x2x2x了,我們需要記錄這個環(huán)在虛樹上的邊數(shù)sss,如果存在兩種不同的邊數(shù)肯定是兩個不同的環(huán),否則就判斷出現(xiàn)次數(shù)>2s>2s>2s),所以我們的復雜度就到了快速的O(n2)O(n^2)O(n2)了。
因為跑不滿并且這是LOJ所以能過。
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; const int N=1e4+10; struct node{int to,next,w; }a[N<<1]; int n,m,tot,cnt,ls[N],dep[N],pos[N]; int las[N],vis[N],dis[N],len[N],c[N]; vector<int> G[N]; void addl(int x,int y,int w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=w;return; } void dfs(int x,int fa){dep[x]=dep[fa]+1;las[x]=fa;int num=0;for(int i=0;i<G[x].size();i++){int y=G[x][i];if(y==fa)continue;if(dep[y]){if(dep[y]>dep[x])continue;if(!pos[x])pos[x]=x;if(!pos[y])pos[y]=y;addl(pos[x],pos[y],1);}else{dfs(y,x);if(pos[y])num=num?-1:pos[y];}}if(!pos[x]&&num<0)pos[x]=x;if(pos[x]){for(int i=0;i<G[x].size();i++){int y=G[x][i];if(y==fa)continue;if(pos[y]&&las[y]==x)addl(pos[x],pos[y],dep[pos[y]]-dep[pos[x]]);}}else pos[x]=num;return; } bool calc(int x,int fa,int t){if(!dep[x])return 1;vis[x]=t;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(i==fa||dep[y]>0||vis[y]==t)continue;bool flag=calc(y,i^1,t);if(flag)return 1;}return 0; } void solve(int x,int fa){if(!calc(x,fa,++cnt))return;for(int i=ls[x];i;i=a[i].next){int y=a[i].to,r=dis[x]+a[i].w;if(i==fa)continue;if(!dep[y]){if(!len[r])len[r]=dep[x]+1;if(len[r]!=dep[x]+1){puts("Yes");exit(0);}c[r]++;if(c[r]>len[r]*2){puts("Yes");exit(0);}}if(dep[y]>=0)continue;dep[y]=dep[x]+1;dis[y]=dis[x]+a[i].w;solve(y,i^1);dep[y]=-1;}return; } int main() { // freopen("4-01.in","r",stdin);scanf("%d%d",&n,&m);tot=1;if(m>n+sqrt(n)*2.0)return puts("Yes")&0;for(int i=1,x,y;i<=m;i++){scanf("%d%d",&x,&y);G[x].push_back(y);G[y].push_back(x);}for(int i=1;i<=n;i++)if(!dep[i])dfs(i,0);memset(dep,-1,sizeof(dep));for(int i=1;i<=n;i++)if(pos[i]==i)dep[i]=0,dis[i]=0,solve(i,0),dep[i]=-1;puts("No");return 0; }總結
以上是生活随笔為你收集整理的Loj#3077-「2019 集训队互测 Day 4」绝目编诗【结论,虚树,鸽笼原理】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CF1654F-Minimal Stri
- 下一篇: 阴阳师食梦貘哪里多 阴阳师食梦貘位置