zoukankan      html  css  js  c++  java
  • CF859E Desk Disorder

    题目

    CF859E Desk Disorder

    分析

    牛逼数数题。

    首先是个人应该就能想到建图,但是我这个傻逼建的图是 (n^2) 级别的,我怎么建的可以自行想象,暂不赘述。

    我们发现,如果我们将每一个位置看做一个点,将题目给出的可以移动的座位 (x->y) 看做一条有向边 ((x,y)) ,那么显然会给出 (n) 条有向边,并且每一个点的出度只能是 (0/1)

    这样的图显然只会有几种情况:树,环,基环树,自环。

    同时我们发现只有当一个点最开始有人时,才会有出度。

    并且,对于两个不同的连通块,它们之间的方案互不影响。

    这启示我们对同一连通块的方案数单独求出来,然后用乘法原理求总方案数。

    现在考虑几种情况单独的方案数:

    对于树来说,如果我们要移动树上某一个点到其父亲,那么其到根的路径上的所有非根节点都要往父亲方向走一步,最后根节点被占据。(因为根节点没有出去的才能作为根节点,说明根节点一开始是空的,而其他节点一开始都一定是有人的。)

    那么树的方案数很显然是 (siz[x]) ,其中 (x) 是树的根节点。

    对于环来说,如果我们要移动环上的任意一个节点,那么整个环都一定会往前走一步,然后也可以整个环都不动,所以方案数为 (2)

    对于基环树来说,其非环上的部分必然不能动,因为这样会出现两个节点去往同一个位置的情况,那么能动的部分其实也只有环上的点,所以与环的情况一样,方案数为 (2)

    对于自环来说,其自身必然不动,方案数显然为 (1) (对于存在自环的树显然也不能动,也是 (1))。

    答案就是每一个连通块的方案数乘积了,注意维护可以使用并查集,具体见代码。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    //#ifdef ONLINE_JUDGE
    //	#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    //	char buf[1<<21],*p1=buf,*p2=buf;
    //#endif
    template<typename T>
    inline void read(T &x){
    	x=0;bool f=false;char ch=getchar();
    	while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
    	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template<typename T>
    inline void write(T x){
    	if(x<0) x=-x,putchar('-');
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define ll long long
    #define ull unsigned long long
    #define ld long double
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define pc putchar
    #define PII pair<int,int>
    #define rep(i,x,y) for(register int i=(x);i<=(y);i++)
    #define dep(i,y,x) for(register int i=(y);i>=(x);i--)
    const int MOD=1e9+7;
    inline int inc(int x,int y){x+=y;return x>=MOD?x-MOD:x;}
    inline int dec(int x,int y){x-=y;return x<0?x+MOD:x;}
    inline void incc(int &x,int y){x+=y;if(x>=MOD) x-=MOD;}
    inline void decc(int &x,int y){x-=y;if(x<0) x+=MOD;}
    inline void chkmin(int &x,int y){if(y<x) x=y;}
    inline void chkmax(int &x,int y){if(y>x) x=y;}
    const int N=2e5+5,M=1e6+5,INF=1e9+7;
    int n,fa[N],fl1[N],fl2[N],siz[N],Ans=1;
    int Getfa(int x){return x==fa[x]?x:fa[x]=Getfa(fa[x]);}
    signed main(){
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    //	ios::sync_with_stdio(false);
    //	double ST=clock();
    	read(n);
    	rep(i,1,n*2) fa[i]=i,siz[i]=1;
    	rep(i,1,n){
    		int x,y,tp=false;read(x),read(y);
    		if(x==y) fl2[x]=true;
    		x=Getfa(x),y=Getfa(y);
    		if(x==y) fl1[x]=true;
    		else fl2[y]|=fl2[x],fa[x]=y,siz[y]+=siz[x],siz[x]=0;
    	}
    	rep(i,1,n*2) if(Getfa(i)==i&&!fl2[i]) Ans=1ll*Ans*(fl1[i]?2:siz[i])%MOD;
    	write(Ans);
    //#ifndef ONLINE_JUDGE
    //	cerr<<"
    Time:"<<(clock()-ST)/CLOCKS_PER_SEC<<"s
    ";
    //#endif
    	return 0;
    }
    /*
    4
    1 2
    2 3
    3 3
    4 3
    */
    
    
    
    
  • 相关阅读:
    java中取两位小数 但不要四舍五入
    从字符串中提取数字 java正则表达式
    SQL实现 列转行(MySQL中)
    sql如何根据时间取出最新的数据记录
    动画 很精辟的
    week 与 strong区别 精辟的解释
    The executable was signed with invalid entitlements新设备run出现这个问题
    在iOS中创建静态库
    网址
    nginx单机1w并发设置
  • 原文地址:https://www.cnblogs.com/Akmaey/p/15477808.html
Copyright © 2011-2022 走看看