fzu 2282(错位排列+逆元+快速幂函数)

 Problem 2282 Wand

Accept: 30    Submit: 94
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

2
1 1
3 1

 Sample Output

1
4
题意:给你一个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(n,i)= i!/(i!*(n-i)!),对于(A/B)mod C,找到B的逆元b=B^-1,求出(A*b)%C即可。
由费马小定理:B 关于 P 的逆元为  B^(p-2);
费马小定理(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),所以:a^-1=a^(p-2);
代码:
#include<cstdio>
#include<vector>
#include<iostream>
const int mod = 1e9 + 7;
const int maxn = 10005;
typedef long long LL;
using namespace std;
LL dp[maxn];
LL inv[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;
        }
        if(cnt==1)
        {
            puts("0");
            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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

童话ing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值