端午节个人赛-山东省省赛 fireworks(杨辉三角形+组合数+逆元)

Description

Hmz likes to play fireworks, especially when they are put regularly.

Now he puts some fireworks in a line. This time he put a trigger on each firework. With that trigger, each firework will explode and split into two parts per second, which means if a firework is currently in position x, then in next second one part will be in position x−1 and one in x+1. They can continue spliting without limits, as Hmz likes.

Now there are n fireworks on the number axis. Hmz wants to know after T seconds, how many fireworks are there in position w?

img 
 

Input

Input contains multiple test cases.

For each test case:

The first line contains 3 integers n,T,w(n,T,|w|≤10^5)

In next n lines, each line contains two integers xi and ci, indicating there are ci fireworks in position xi at the beginning(ci,|xi|≤10^5).

 

Output

For each test case, you should output the answer MOD 1000000007.

 

Example Input

1 2 0
2 2
2 2 2
0 3
1 2

 

Example Output

2
3

 

题意

烟花在每秒都会分裂一次,并且分裂成的两半刚好落在相邻的两点,然后它们也可以继续分裂。

给出 n 个点烟花的初始数量,问经过 T 秒后在点 w 有多少数量的烟花。

 

思路

考虑所有的烟花分裂都是一样的,并且其分裂之后所形成的局势仅和时间有关。

所以我们只需要关心一个烟花是如何分裂的:

0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 1 0 0 0 0
0 0 0 1 0 2 0 1 0 0 0
0 0 1 0 3 0 3 0 1 0 0
0 1 0 4 0 6 0 4 0 1 0

第几行代表第几秒,行中的每个数字代表当前时间该点烟花的数量,于是我们发现了一个中间插入了 0 的杨辉三角,计算方法也就是组合数咯~

从上面的矩阵我们可以发现,当时间与距离同奇偶的时候才处于杨辉三角中,其余情况都为 0 。


因为题目中数据比较大,所以计算组合数需要用到乘法逆元,先打表求出 n! ,然后根据组合数公式计算即可。

  注意点:

1、理解逆元的概念,知道杨辉三角形与组合数的对应关系;

对于正整数,如果有,那么把这个同余方程中的最小正整数解叫做的逆元。

逆元一般用扩展欧几里得算法来求得,如果为素数,那么还可以根据费马小定理得到逆元为

     

2、大数据,%mod多多益善

3、思路清晰,分块写,稳一点

4、读懂题意!!

#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <stdlib.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll j[101000], ex[101000];

ll ppow(ll a, ll b)                        //求快速幂
{
    //cout << a << " " << b <<endl;
    a %= mod; b %= mod;
    ll ans = 1;
    while(b)
    {
        if(b&1) ans = (ans % mod * a) % mod;
        a = a * a % mod;
        b /= 2;
    }
   // cout << "PP" << ans << endl;
    return ans % mod;                           
}

void init()                                  //初始化n!的值和 n!取模1e9+7时的逆元
{
    j[0] = ex[0] = 1;
    for(int i = 1; i <= 100005; i ++ )
    {
        j[i] = i * j[i-1] % mod;
        ex[i] = ppow(j[i], mod - 2) % mod;
    }
    return ;
}


int C(int n, int m)                    //求组合数 C(N, M);
{
    if(n == m) return 1;
    ll ans = j[n] % mod * ex[n-m] % mod * ex[m] % mod;
    //cout << j[n] << " " << ex[n-m] <<" " << ex[m] << endl;
    //cout << "CC" << ans << endl;
    return ans;
}


int main()
{
  //  freopen("1.txt", "r", stdin);
    int n, t, w;
    init();
    //cout << ex[1] << endl;
    while(cin >> n >> t >> w)
    {
        int c, x;
        ll ans = 0;
        for(int i = 1; i <= n; i++)
        {
            int c, x;
            cin >> x >> c;
            int k = abs(w - x) % mod;
            if(k > t || (k&1) != (t&1) || !c) continue;         //注意如果 k和t奇偶性不同或者k > t的话ans是不会变化的
            ans += c % mod * C(t, (k + t) / 2) % mod;      //我也不知道为什么 c 后面加了个 %mod 就不会wa了2333....
            ans %= mod;
        }
        cout << ans % mod << endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值