2017山东省第八届ACM省赛 fireworks(杨辉三角 + 逆元)

fireworks

Time Limit: 1000MS  Memory Limit: 65536KB
Problem 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
Hint
Author
“浪潮杯”山东省第八届ACM大学生程序设计竞赛(感谢青岛科技大学)

思路:写一下小球的爆炸过程,可以发现小球的爆炸符合杨辉三角,即小球爆炸后t秒的规律就是杨辉三角的第t层。每个小球都符合这样的规律,对于不同位置的小球爆炸是相互独立的,答案就是每个小球爆炸t秒后在位置w的个数。由于组合数比较大故需要求逆元来代替除法取模。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include<vector>
#include<cmath>
#include<set>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 1299709 + 10;
const int maxt = 100200;
const int inf = 0x3f3f3f3f;
const ll INF = 0x7f7f7f7f7f7f7f7f;
const int mod = 1e9 + 7;
const double pi = acos(-1.0);
const double eps = 1e-8;
int a[maxn];
ll C[maxn];
ll quick_mod(ll x, int n){
    ll ret = 1;
    while(n){
        if(n & 1) ret = ret * x % mod;
        x = x * x %mod;
        n >>= 1;
    }
    return ret;
}
void init(int t){
    C[0] = 1;
    for(int i = 1; i <= t; ++i){
        C[i] = C[i - 1] * (t - i + 1) % mod * quick_mod(i, mod - 2) % mod;
    }
}
ll solve(ll x, int w, int l){
    int d = abs(x - w);
    ll sum = 0;
    if(l & 1){
       if(d < l && d % 2 == 0)
            sum += C[l / 2 - d / 2];
    }
    else{
        if(d < l && d & 1)
            sum += C[l / 2 + (d - 1) / 2];
    }
    return sum;
}
int main(){
    int n, t, w;
    while(scanf("%d%d%d", &n, &t, &w) == 3){
        ll ans = 0;
        init(t);
        for(int i = 0; i < n; ++i){
            int x, c;
            scanf("%d%d", &x, &c);
            ans += c * solve(x, w, t + 1);
            ans %= mod;
        }
        printf("%lld\n", ans);
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值