• CodeForces-568B Symmetric and Transitive


    题目描述

    要求找出 (n) 个元素中满足对称性,传递性,但不满足自反性的所有二元关系种数。

    有一个集合,它的元素是二元关系((x,y)),其中(x,y)的范围是([1,n])。这个集合满足如下性质:
    1.如果这个集合里有((x,y)),那么一定有((y,x))
    2.如果这个集合里同时有((x,y))((y,z)),那么一定有((x,z))。注意,在这条性质里,(x,y,z)可以相等
    3.这个集合不同时包含((1,1),(2,2),……(n,n))
    问这个集合有多少种组成方式。
    (当(n=3)时,有(10)种方式,为∅, {(1,1)} , {(2,2)} , {(3,3)} , {(1,1),(2,2)} , {(1,1),(3,3)} , {(2,2),(3,3)} , {(1,2),(2,1),(1,1),(2,2)} , {(1,3),(3,1),(1,1),(3,3)} , {(2,3),(3,2),(2,2),(3,3)})。

    Input

    输入 (n) ,表示有 (n) 个元素, ((1<=n<=4000)).

    Output

    输出满足对称性,传递性,但不满足自反性的所有二元关系种数。

    注意,答案可能很大,需要模 1e9+7,即1000000007

    Sample Input

    1
    2
    3
    

    Sample Output

    1
    3
    10
    

    首先,我们发现,若一个集合中有二元关系((x,y)),则就一定有((y,x)),有((x,x))((y,y))

    也就是说,一个集合中所有的元素必定会形成((1,1)),((2,2))......这样的关系。

    而题目中要求集合不能同时包含((1,1),(2,2),……(n,n)),实际上就是说集合中不能包含(1-n)所有的元素。

    而这个我们可以利用贝尔数组解决。

    定义:(dp[i][j])表示前(i)个数分成(j)个集合的方案数。

    考虑转移:对于第(i)个元素,我们有两种决策:

    1.我们将其放入前面已经有的(j)个集合中。

    2.我们们新建一个集合,将其放入。

    所以我们有:(dp[i][j]=dp[i-1][j-1]+j*dp[i-1][j])

    而我们要求的答案是(n)个元素不能在同一个集合的方案数。

    对于我们要求的答案,我们可以转换成,在(n)个数中选了(i)个数,这(i)个数分割成若干个集合,而剩下的(n-i)个数独立成为一个集合的方案数,((i!=n))

    则答案就为(sum_{i=1}^{n-1}C(n,i)*bell(i))

    代码如下

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define int long long
    #define reg register
    #define Raed Read
    #define debug(x) cerr<<#x<<" = "<<x<<endl;
    #define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
    #define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
    #define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
    #define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
    
    inline int Read(void) {
    	int res=0,f=1;
    	char c;
    	while(c=getchar(),c<48||c>57)if(c=='-')f=0;
    	do res=(res<<3)+(res<<1)+(c^48);
    	while(c=getchar(),c>=48&&c<=57);
    	return f?res:-res;
    }
    
    template<class T>inline bool Min(T &a,T const&b) {
    	return a>b ?a=b,1:0;
    }
    template<class T>inline bool Max(T &a,T const&b) {
    	return a<b?a=b,1:0;
    }
    
    const int N=4e3+5,M=3e5+5,mod=1e9+7;
    
    bool MOP1;
    
    int dp[N][N],F[N],Fac[N];
    
    inline int Pow(int x) {
    	int res=1,y=mod-2;
    	while(y) {
    		if(y&1)res=(res*x)%mod;
    		x=(x*x)%mod,y>>=1;
    	}
    	return res;
    }
    
    inline int C(int x,int y) {
    	if(!x)return 1;
    	return (Fac[y]*Pow((Fac[x]*Fac[y-x])%mod))%mod;
    }
    
    bool MOP2;
    
    inline void _main(void) {
    	dp[0][0]=1,F[0]=1,Fac[0]=1;
    	rep(i,1,4000)Fac[i]=(Fac[i-1]*i)%mod;
    	rep(i,1,4000)rep(j,1,4000) {
    		dp[i][j]=(dp[i-1][j-1]+j*dp[i-1][j])%mod;
    		F[i]=(F[i]+dp[i][j])%mod;
    	}
    	int n;
    	while(~scanf("%lld",&n)) {
    		int Ans=0;
    		ret(i,0,n)Ans=(Ans+(C(i,n)*F[i])%mod)%mod;
    		printf("%lld
    ",Ans);
    	}
    }
    
    signed main() {
    	_main();
    	return 0;
    }
    
  • 相关阅读:
    HTTP接口测试
    1 ThinkPHP MVC框架初识
    解决python2.7 scripts和pip缺失问题
    图片重绘
    Oracle数据库提权
    二阶注入
    去重算法,简单粗暴&优化版
    常用集合
    冒泡排序 -- 算法原理
    MySQL-配置环境变量及修改密码(附-mysql安装教程)
  • 原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11429642.html
Copyright © 2020-2023  润新知