1. 程式人生 > >【cf859E】Desk Disorder

【cf859E】Desk Disorder

n-1 portal iostream string max 計算 urn ++i 位置

Portal --> cf859E

Solution

??  我們可以將每一個人看成一條邊,將位置看成點,然後一個人在新的方案中可以選擇的位置就是這條邊連接的兩個點,然後我們就得到了一個圖

?  註意到這個圖可能包含多個連通塊,每個連通塊可以獨立計算,那麽最後的答案應該就是各個連通塊計算結果的乘積,那麽現在我們的問題就是怎麽算一個連通塊內的答案

??  考慮一個包含\(n\)個點的連通塊,我們來分析一下這個連通塊的性質:首先因為這是一個連通塊,所以邊數\(m>=n-1\),然後註意到這題中有一個性質:原方案中沒有兩個人選的是同一個位置(點),所以我們可以得到邊數\(m<=n\)

?  所以一個包含\(n\)個點的連通塊只可能有兩種情況:

1、\(m=n-1\):這個時候是一棵樹,那麽答案就應該是\(n\)(樹中的節點個數),具體的話就是考慮哪個節點沒有人選,所以就有\(n\)種方案

2、\(m=n\):這個時候如果是一個基環樹,考慮環中的邊數和點數相同,所以環中所有的點只能被環上的邊選,這樣一來樹中能選的點數和要選的邊數相等,所以樹中的方案是唯一的,環中的方案只有兩種,所以這個時候有\(2\)中方案;但是!如果說這個環是個自環,那就只有一種方案了,因為環中不能移動

?  所以我們直接並查集判斷一下統計一下就好了

?  

??  代碼大概長這個樣子

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+10,MOD=1e9+7;
int f[N*2],in[N*2],cnt[N*2],mark[N*2];
int n,m,tot,ans;
int get_f(int x){return f[x]=f[x]==x?f[x]:get_f(f[x]);}
int mul(int x,int y){return 1LL*x*y%MOD;}

int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    int x,y;
    scanf("%d",&n);
    for (int i=1;i<=2*n;++i) f[i]=i,cnt[i]=1,mark[i]=0;
    ans=1;
    int tmp=0;
    for (int i=1;i<=n;++i){
        scanf("%d%d",&x,&y); 
        get_f(x); get_f(y);
        mark[x]=1;
        tmp=max(tmp,max(x,y));
        if (x==y) continue;
        if (f[x]==f[y]) ans=mul(ans,2);
        cnt[f[y]]+=cnt[f[x]];
        f[f[x]]=f[y];
    }
    int debug=0;
    for (int i=1;i<=2*n;++i)
        if (!mark[i])
            ans=mul(ans,cnt[i]),++debug;
    printf("%d\n",ans);
}

【cf859E】Desk Disorder