2015年秋校赛第4题

4.Broken array

Description

There are n (n < = 10000) different books on n different shelves. Books number from 1 to n, so do shelves. Every shelf has one book. Originally, the book i on the shelf i. Now, let’s rearrange the books. The request is to make every book not be in the original position. For example, there are 4 books and the original permutation is 1,2,3,4 . When we rearrange, the permutation 2,3,4,1 is legal, but the permutation 1,3,4,2 is illegal. We want to know how many different legal permutations exist (The answer needs to modulo 1000000007)?

Input

The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. Then T(0<T <= 100) tests cases follow. Next T line, every line contains a integer n(1<=n<=10000),which denotes the number of books.

Output

Print a integer m for every case, and m denotes the number of legal permutations.

Sample Input

4
1
3
5
10

Sample Output

0
2
44
1334961
 
分析:其实这是一个全错排的问题,也是欧拉提出的信封问题。解决这个问题其实可以用递归的想法:我们记对于n个元素全错排的种数一共有M(n)种方法。对于n个元素,如果一开始从第n个开始排,因为要求全错排,那么它只有n-1中放法。我们假设它放到了k这个位置。那么对于原先放在k这个位置的元素k来说,它现在有两种选择:(1)如果放到n的位置上,那么接下来的问题就是剩下的n-2个元素的全错排。那么共有M(n-2)种方法。(2)如果k并没有放到n这个位置上,那么其实就是(n-1)个元素进行全错排,那么有M(n-1)种方法。那么M(n)=(n-1)*[M(n-1)+M(n-2)].
  其实这时候我们已经找到解决问题的方法了,但因为数据过大,所以我们减少程序的运行时间还得进行进一步的优化。所以可以用数组来储存每一次的结果,那么当下一次递归到这种情况的时候,就可以直接返回答案,而不需要计算。
代码如下:
#include <stdio.h>
long long score[10005]={0};
long long erratum(int n)
{
    if(score[n]!=0)
        return score[n];
    else{
        if(n==1)
            score[n]=0;
        else if(n==2)
            score[n]=1;
        else{
            score[n]=((n-1)*(erratum(n-1)%1000000007+erratum(n-2)%1000000007))%1000000007;
        }
    }
    return score[n];
}
int main()
{
    int T,n;
    long long ret;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        ret=erratum(n);
        printf("%I64d
",ret);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kugwzk/p/5076135.html