zoj 3688 The Review Plan II 组合数学

我的解法比较慢。 复杂度 O(nlgn) 有O( N )的解法  递推公式看不懂

此题是 有 禁位 的排列 。相当于在 n*n的棋盘中  设置了 2n 个 禁位。

有 k个在 这 2*n 个禁位中 的排列数  Pk。 这 2*n 个 禁位 可以看成  一个有 t =2*n 个点 形成的环中 ,选出k个不相邻的组合数。

可以通过 枚举圆上的 点 就将 圆拆分成了链。

  先选取一个点  有 t 种情况。 选了这个点之后 剩余 t-3 个点 ,形成一条链 。 从中选k-1 个不相邻的点, C(t- k-1 , k-1)

  由于对于 每种组合 都 枚举够k 次。则  从 t 个点的环中 ,选k个不相邻的点的组合数是 Pk = t * C( t-  k - 1, k -1 ) / k

  最终的结果就是  P0 - p1 + p2 - P3 + P4 ......... 利用容斥原理求解

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#define REP(i,n) for(int i=0;i>1;
    }
    return ret;
}
const int maxn = 200100;
LL f[maxn];
void init(){
    f[0] =1;
    for(int i=1;i<=maxn;i++){
        f[i] = i*f[i-1];
        f[i]%= mod;
    }
}
void solve(int n){
    LL ans = 0;
    int t = 2*n;
    for(int k = 0 ;k<= n;k++){
        LL up = t *f[t-k-1];
        up%= mod;
        LL down = f[k]*f[t- 2*k];
        down%= mod;   
        down = pow(down , mod-2);
        up = up *down;
        up%= mod;
        up*= f[n-k];
        up%= mod;
        if(k&1){
            ans -= up;
            ans = (ans + mod)%mod;
        }else{
            ans += up;
            ans%= mod;
        }
    }
    printf("%d\n",(int)ans);
}
int n;
int main(){ 
    init();
    while(~scanf("%d",&n)){
        if(n==1){
            cout << 0 <



你可能感兴趣的:(组合数学)