• 【cf859E】Desk Disorder


    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
    ",ans);
    }
    
  • 相关阅读:
    vi—终端中的编辑器
    CSS Selector
    转: 通过WMI获取网卡MAC地址、硬盘序列号、主板序列号、CPU ID、BIOS序列号
    WMI入门教程之WMI中的类在哪里?
    WMI测试器
    WMI Explorer操作 和 powershell命令
    C++ WMI获取系统硬件信息(CPU/DISK/NetWork etc)
    使用C++进行WMI查询的简单封装
    ubuntu版本信息查看
    win10 修改文件夹右击默认打开程序
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9543299.html
Copyright © 2020-2023  润新知