[组合数学]选课

题目描述

你真的认为选课是那么容易的事吗?HYSBZ的ZY同志告诉你,原来选课也会让人产生一种想要回到火星的感觉。假设你的一周有n天,那么ZY编写的选课系统就会给你n堂课。但是该系统不允许在星期i和星期i+1的时候选第i堂课,也不允许你在星期n和星期一的时候选第n堂课。然后连你自己也搞不清哪种选课方案合法,哪种选课不合法了。你只想知道,你到底有多少种合法的选课方案。

Input
有多组数据,请读到文件末结束。
对于每组数据仅一行,1个正整数 n。

Output
对于每组输出只有一行,1个非负整数,为选课方案数量 mod (10^9+7).

Sample Input
2
4

Sample Output
0
2

【样例解释】
对于样例二:
周一上第二堂课,周二上第三堂课,周三上第四堂课,周四上第一堂课;
周一上第三堂课,周二上第四堂课,周三上第一堂课,周四上第二堂课。
共2种选课方案。

Data Constraint
对于第i组数据,n<=10*i, 1<=i<=3
对于100%的数据:1<=n<=100000

分析

别看了我这是在WC里推规律的
若要看解析请移步

#include 
#include 
#define rep(i,a,b) for (i=a;i<=b;i++)
typedef long long ll;
const ll MOD=1e9+7;
using namespace std;
ll fact[200001],ny[200001],factny[200001];

ll Power(ll x,ll y) {
    ll ans=1;x%=MOD;
    while (y) {
        if (y&1) ans=ans*x%MOD;
        x=x*x%MOD;
        y>>=1;
    }
    return ans;
}

ll C(int n,int m) {
    return fact[n]*factny[m]%MOD*factny[n-m]%MOD;
}

int main() {
    int i,n;
    fact[0]=factny[0]=1;
    rep(i,1,200000)
    fact[i]=fact[i-1]*i%MOD,ny[i]=Power((ll)i,MOD-2)%MOD,factny[i]=factny[i-1]*ny[i]%MOD;
    while (scanf("%d",&n)!=EOF) {
        ll ans=0;
        if (n>1) rep(i,0,n)
        if (i&1) ans=(ans-2ll*n*ny[2*n-i]%MOD*C(2*n-i,i)%MOD*fact[n-i]%MOD)%MOD;
        else ans=(ans+2ll*n*ny[2*n-i]%MOD*C(2*n-i,i)%MOD*fact[n-i]%MOD)%MOD;
        printf("%lld\n",(ans+MOD)%MOD);
    }
}

你可能感兴趣的:([组合数学]选课)