题目描述
要求找出 (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;
}