FZU 2301-Chosen by god(由神来选择) (二项分布+逆元)

Everyone knows there is a computer game names "hearth stone", recently xzz likes this game very much. If you want to win, you need both capacity and good luck.

每人都知道有一个游戏叫做“炉石传说”(贵游大佬orz),最近小粽子很喜欢这个游戏,如果你想赢的话,你既得有本事又得有欧气(好运)。

There is a spell card names "Arcane Missiles", which can deal 3 damagens randomly split among all enemies.

有一张符卡叫做奥术飞弹 恋符「非定向光线」~non-directional lasers,这张符卡可以给对方所有敌人总共造成3点伤害,每个单位受到的伤害随机。

xzz have a "Arcane Missiles Plus" can deal n damage randomly split among all enemies. The enemy battle field have only two characters: the enemy hero and enemy minion.

 

小粽子有一张真·奥术飞弹,可以给把n点伤害随机分配到敌方每个单位上。战场上只有两个角色:敌人的英雄和敌人的奴隶

Now we assume the enemy hero have infinite health, the enemy minion has m health.

现在我们假定对方英雄不死(有无限生命值),对方奴隶有m点生命值

xzz wants to know the probability of the "Arcane Missiles Plus" to kill the enemy minion (the minion has not more than 0 health after "Arcane Missiles Plus"), can you help him?

小粽子想知道这张真·奥术飞弹干翻对方小兵的概率,你能帮帮他吗?

Input

The first line of the input contains an integer T, the number of test cases. T test cases follow. (1 ≤ T ≤ 100000)

输入的第一行包括一个整数T:测试实例的个数。

Each test case consists of a single line containing two integer n and m. (0 ≤ m ≤ n ≤ 1000)

每个测试实例只有一行输入,包括两个整数n,m

Output 

For each test case, because the probability can be written as x / y, please output x * y^-1 mod 1000000007. .(y * y^-1 ≡ 1 mod 10^9 + 7)

对于每个测试实例,因为这个概率能写成x/y的分数形式,请输出x*(y^-1)mod(1e9+7)的结果(在这里的y^-1是指y在mod 1e9+7情况下的逆元。)

Sample Input

2
3 3
2 1

Sample Output

125000001
750000006

既然要把对面的小兵摁死,那么单回合内对它造成的伤害不能低于它的生命值,换言之,对它造成比生命值大的伤害的情况都是符合条件的。如是这般我们就知道了在[m,n]这个区间内的每种可能事件都要纳入统计范围。

再来看一下这个概率模型。根据Spell card:奥术飞弹的介绍,这张符卡的攻击模式是发出三发飞弹,每一发对随机单位造成伤害。所以基本事件空间Ω的大小为(2的n次幂),由于每个事件相互独立且每一回合仅有两种状态,所以断定这是二项分布模型。

好了,这就好办了,高中我们都深入了解过这种模型的计算与性质,这个题解了一半。余下一个逆元的问题。首先我们看到1E9+7是一个质数,因此无论同余方程ax\equiv1(mod(1e9+7))左边的a为何值,a的逆元x总存在。

求逆元有三种通用办法:

  • 扩展欧几里得定理
  • 费马小定理
  • 根据特殊公式,线性筛选

由于我们在求基本事件空间的大小时用到了快速幂算法,所以我们正好借现有的快速幂来实现费马小定理。

所以整个题目的思路就很清晰了:

  1. 利用杨辉三角的组合数公式来对1007(多打一点)以内的组合数打表
  2. 利用快速幂通过费马小定理求分母的逆元。
  3. 对基本事件空间中所有符合条件的可能事件的个数求和,然后解得答案

代码如下:

#include 
#include 
//#include 
#include 
#include 
#include 
#include 
#include 
#define DETERMINATION main
#define lldin(a) scanf("%lld",&a)
#define din(a) scanf("%d",&a)
#define printlnlld(a) printf("%lld\n",a)
#define printlnd(a) printf("%d\n",a)
#define printlld(a) printf("%lld",a)
#define printd(a) printf("%d",a)
#define reset(a,b) memset(a,b,sizeof(a))
const int INF=0x3f3f3f3f;
using namespace std;
const double PI=acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod=1000000007;
///Schlacht von Stalingrad
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
ll combinatorial[1009][1009];
ll quickpower(ll a,ll b)
{
    ll ans=1;
    a%=mod;
    while(b)
    {
        if(b&1)
            ans=(a*ans)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return ans;
}
void combinatorial_generator()
{
    combinatorial[0][0]=1;
    for(int i=0; i<=1007; i++)//虽然不知道为什么要打0,但是一定要把0的组合数打出来,
//否则很可能答案错误
    {
        combinatorial[i][0]=combinatorial[i][i]=1;
        for(int j=1; j<=i; j++)
            combinatorial[i][j]=(combinatorial[i-1][j]+combinatorial[i-1][j-1])%mod;
    }
}
int DETERMINATION()
{
    cin.ios::sync_with_stdio(false);//数据量较大,取消同步来加速。
    ll t;
    cin>>t;
    combinatorial_generator();
    while(t--)
    {
        ll n,m;
        cin>>n>>m;
        ll denominator=quickpower(2,n);//分母大小
        ll numerator=0;
        for(int i=m; i<=n; i++)
            numerator=(numerator+combinatorial[n][i])%mod;//所有可能事件的总和。
        ll inv=quickpower(denominator,mod-2)%mod;//费马小定理
        cout<<(numerator*inv)%mod<

 

你可能感兴趣的:(数学,乘法逆元)