zoj 3688 The Review Plan II


zoj 3688 The Review Plan II


Michael is very grateful for your last help of his review plan. Now he finds that it's interesting to do the review in a different way than ordinary students, he wants you to help him again.

The whole book he needs to review hasN chapters, he wants to arrange exactlyN days to take his review, and one chapter by each day.

But he does not want to read theith(1 ≤i ≤ N-1) chapter in the ith day or the(i+1)th day. And read theNth chapter in theNth day or in the first day is not acceptable too. Can you tell him how many different appropriate plans he could make ? 

Input

There are multiple test cases. For each test case there is a single line contains one integerN(1 ≤N ≤ 100000), N is the number of the days and also the number of the chapters in the book. Process to the end of input.

Output

     One line for each case. The number of the different appropriate plans module 1000000007.

Sample Input

     2

     4

Sample Output

     0

     2

Hint

     For case 1, there is no such plan. For case 2, you can arrange the plan as (2, 3, 4, 1) or (3, 4, 1, 2).




思路:  根据题意,我们在复习  第 i 章  不能是第 i+1  和  i  Day,那么由容斥原理 , 假设有一堂课错误,那么就有: C(n,1) *(n-1)!;

那么对于有k门课错误的时候就有相当于k 个 的禁位排列,那么所有可能出现的错误情况应该有2*n  种,即假设第一章的为 1或 n天,第二章的 为 2 或 3天,那么问题就变成了  从 2n 个圆中选取  k 个不相邻的数的方法数。

zoj 3688 The Review Plan II_第1张图片


由定理: 即我们可以利用容斥原理,从 1~n 遍历一遍,在奇数的时候减,偶数的时候加, 每一项应该表示为  C(2*n-k-1,k-1) *(n-k)! 对于前面的一项有解释,那么对于后面的那个:(n-k)!  —— 其实就是在 n 个中去掉 k 个特殊情况后剩余的元素进行排列即,(n-k)!,也就是剩下的 n-k  个章节可以随便排列; 注意的是 对于组合数的计算,需要使用费马小定理。 听说还可以找规律,然而我不会,,,,,,


#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 401000
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define ll long long
using namespace std;


ll f[maxn];
void init()
{
    f[0]=1;
    for(int i=1;i>=1;
    }
    return tem%MOD;
}
int main()
{
    init();
    int n;
    while(scanf("%d",&n)!=EOF)
    {

        if(n<=2) puts("0");
        else
        {
            ll ans=f[n];
            for(int i=1;i<=n;i++)
            {
                ll sum=f[2*n-i-1]*Pow(f[i-1],MOD-2)%MOD;
                sum=sum*2*n%MOD;
                sum=sum*Pow(i,MOD-2)%MOD;
                sum=sum*f[n-i]%MOD;
                sum=sum*Pow(f[2*n-2*i],MOD-2)%MOD;
                if(i&1)
                    ans=((ans-sum)%MOD+MOD)%MOD; // 注意减的时候可能出现负数
                else
                    ans=(ans+sum)%MOD;
            }
            cout<



 







你可能感兴趣的:(禁位排列)