Chat Group(CFGym 101775A ) (费马小定理求逆元)

It is said that a dormitory with 6 persons has 7 chat groups ^_^. But the number can be even larger: since every 3 or more persons could make a chat group, there can be 42 different chat groups.

Given N persons in a dormitory, and every K or more persons could make a chat group, how many different chat groups could there be?

Input

The input starts with one line containing exactly one integer T which is the number of test cases.

Each test case contains one line with two integers N and K indicating the number of persons in a dormitory and the minimum number of persons that could make a chat group.

  • 1 ≤ T ≤ 100.
  • 1 ≤ N ≤ 109.
  • 3 ≤ K ≤ 105.

Output

For each test case, output one line containing "Case #x: y" where x is the test case number (starting from 1) and y is the number of different chat groups modulo 1000000007.

Example

Input

1
6 3
Output

Case #1: 42

题意:n个人的小组,最少m个可以组成一组,问共有多少种方法。

思路:就是求C(n,k) + C(n,k+1) +...+ C(n,n);但是数据量超大,我们可以转换一下

 2^n - ( C(n,0) + C(n,1) + ... + C(n,k-1) )而C(n,k) = ( n*(n-1)*..(n-k+1) ) / ( k! );因为要除以k的阶乘,所以就用到了费马小定理求逆元,除以一个很大的数就是乘以它的逆元。最好是把逆元预处理一下就不会超时了。

用费马小定理求逆元

费马小定理公式:a^(p-1) ≡ 1(mod p)

逆元公式:H * B ≡ 1  (mod M)   -->这里假设M为质数,由公式显然B与M互质

其中M = p,B = a

联立可得H * a ≡ a^(p - 1)(mod p)

同时除以a(显然a mod p 不为0)

最终得B(或者a)关于p的逆元

H ≡ a^(p - 2)(mod p)

AC代码:

/***
 * ┌───┐   ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐
 * │Esc│   │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│  ┌┐    ┌┐    ┌┐
 * └───┘   └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘  └┘    └┘    └┘
 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐
 * │~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │N L│ / │ * │ - │
 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤
 * │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │   │
 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │
 * │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter  │               │ 4 │ 5 │ 6 │   │
 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤     ┌───┐     ├───┼───┼───┼───┤
 * │ Shift  │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│  Shift   │     │ ↑ │     │ 1 │ 2 │ 3 │   │
 * ├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││
 * │ Ctrl│    │Alt │         Space         │ Alt│    │    │Ctrl│ │ ← │ ↓ │ → │ │   0   │ . │←─┘│
 * └─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘
 */
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
#define inf 0x3f3f3f3f
#define PI acos(-1)
const int mod=1e9+7;
const int M=1e5 + 10;
typedef long long ll;
ll a[M]={0};
ll F(ll a, ll b)
{
    ll ans = 1;
    a %= mod;
    while(b){
        if(b&1)
            ans = ((a%mod) * ans) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return ans % mod;
}
void init(){//预处理逆元
    ll p = 1;
    for (ll i = 1; i <= 1e5;i++){
        p = (p * i) % mod;
        a[i] = F(p, mod - 2) % mod;
        if(a[i]<0)
            a[i] += mod;
    }
}
int main()
{
    ll T, n, k;
    init();
    scanf("%lld", &T);
    for (int kk = 1; kk <= T; kk++)
    {
        scanf("%lld%lld", &n,&k);
        ll ans = F(2, n) - 1;//先减去C(n,0)的情况
        ll p = 1, q = 1;
        for (ll i = 1; i < k; i++){
            p = ((p % mod) * (n - i + 1)) % mod;
            q = (q * i) % mod;
            ans = ans - (p % mod * (a[i] % mod)) % mod;
            if (ans < 0)
                ans += mod;
        }
        printf("Case #%d: %lld\n", kk, ans%mod);
    }
    return 0;
}
发布了350 篇原创文章 · 获赞 715 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/ZCY19990813/article/details/100008375