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?
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;
}