FZU 2282Problem 2282 Wand(错排+快速幂+费马小定理)

来源:互联网 发布:mysql如何安装 编辑:程序博客网 时间:2024/06/03 15:07
Problem 2282 Wand

Accept: 132    Submit: 463
Time Limit: 1000 mSec    Memory Limit : 262144 KB

 Problem Description

N wizards are attending a meeting. Everyone has his own magic wand. N magic wands was put in a line, numbered from 1 to n(Wand_i owned by wizard_i). After the meeting, n wizards will take a wand one by one in the order of 1 to n. A boring wizard decided to reorder the wands. He is wondering how many ways to reorder the wands so that at least k wizards can get his own wand.

For example, n=3. Initially, the wands are w1 w2 w3. After reordering, the wands become w2 w1 w3. So, wizard 1 will take w2, wizard 2 will take w1, wizard 3 will take w3, only wizard 3 get his own wand.

 Input

First line contains an integer T (1 ≤ T ≤ 10), represents there are T test cases.

For each test case: Two number n and k.

1<=n <=10000.1<=k<=100. k<=n.

 Output

For each test case, output the answer mod 1000000007(10^9 + 7).

 Sample Input

21 13 1

 Sample Output

14

 Source

第八届福建省大学生程序设计竞赛-重现赛(感谢承办方厦门理工学院)
题意:
大概转化为给你一个n代表编号为1-n的有序的n个人,一个k,重新排序之后,询问至少有k人在自己原来位置的方案数。
想法:
n个人不在自己位置上:错排F(n)=(i-1)*(F(n-1)+F(n-2)) (n>=2) 特殊的,F(0)=1,F(1)=0;
每个错排的组合数C(m,n)=n!/((n-m)!*m!)=n!*(n-m)!^(-1)*m!^(-1)
费马小定理(Fermat Theory)是数论中的一个重要定理,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。所以,a^-1*a=1=a^(p-1)%p,所以:a^-1=a^(p-2)%p;
再用快速幂解决a的幂
代码:
#include<cstdio>
const int mod = 1e9 + 7;
const int maxn = 10005;
typedef long long LL;
LL dp[maxn];
int n,k;
LL pri[maxn];
LL ni[maxn];
LL pow(LL a,int b)
{
    LL ans=1,base=a;
    while (b>0)
    {
        if (b%2==1)
            ans=(base*ans)%mod;
        base=(base*base)%mod;
        b/=2;
    }
    return ans;
}
void s()   //打表
{
    pri[0]=1;
    ni[0]=1;
    for (int i=1;i<=maxn ;i++)
    {
        pri[i]=pri[i-1]*i%mod;  //N!
        ni[i]=pow(pri[i],mod-2);
    }
}
int main()
{
    s();
    int T;
    scanf("%d", &T);
    dp[0]=1,dp[1] = 0;
    for(int i = 2; i <= maxn; i++)
    {
        dp[i] = ((i - 1) * (dp[i - 1] + dp[i - 2])) % mod;
    }
    while(T--)
    {
        LL ans=1;
        scanf("%d%d", &n, &k);
        int cnt = n - k;
        if(cnt==0)
        {
            puts("1");
            continue;
        }
        for(int i=2;i<=cnt;i++)
        {
            LL sum=((pri[n]*ni[i]%mod)*ni[n-i])%mod;
            //printf("%lld\n",sum);
            ans+=(sum*dp[i])%mod;
        }
        printf("%lld\n",ans%mod);
    }
    return 0;
}

原创粉丝点击