fireworks-山东省第八届省赛C-组合数学

fireworks

Time Limit: 1000 ms  Memory Limit: 65536 KiB
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.

Sample Input
1 2 0
2 2
2 2 2
0 3
1 2
Sample Output
2
3
Hint
Source

“浪潮杯”山东省第八届ACM大学生程序设计竞赛(感谢青岛科技大学)

题意:

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

给出 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! ,然后根据组合数公式计算即可。

(思路来自千千)

代码:

#include<bits/stdc++.h>
using namespace std;
/// IO Input and Output
namespace IO
{
    template <typename T>
    inline bool scan_d (T &ret)
    {
        char c;
        int sgn;
        if (c = getchar(), c == EOF)return false; //EOF
        while (c != '-' && (c < '0' || c > '9') )
            if((c = getchar()) == EOF) return false;
        sgn = (c == '-') ? -1 : 1;
        ret = (c == '-') ? 0 : (c - '0');
        while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
        ret *= sgn;
        return true;
    }

    template<typename T>
    void print(T x)
    {
        static char s[33], *s1;
        s1 = s;
        if (!x) *s1++ = '0';
        if (x < 0) putchar('-'), x = -x;
        while(x) *s1++ = (x % 10 + '0'), x /= 10;
        while(s1-- != s) putchar(*s1);
    }

    template<typename T>
    void println(T x)
    {
        print(x);
        putchar('\n');
    }
};

typedef long long ll;
const int maxn = 2e5+10;
const ll mod = 1e9+7;
ll arr[maxn],tot;
ll fac[maxn],inv[maxn];
ll power(ll a,ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
void init() {
    fac[0] = fac[1] = 1;
    inv[0] = inv[1] = 1;
    for(int i=2;i<maxn;i++) {
        fac[i] = fac[i-1] * i % mod;
        inv[i] = power(fac[i],mod-2);
    }
}
ll C(ll n,ll m) {
    return fac[n] * (inv[m] * inv[n-m] % mod) % mod;
}
void init_t(int t) {
    memset(arr,0,sizeof(arr));
    tot = 0;
    int len = t / 2;
    if(t % 2 == 0) arr[tot++] = C(t,len--);
    for(int i = len;i >= 0;i--)
        arr[tot++] = 0,arr[tot++] = C(t,i);
}
int main()
{
    init();
    int n,t,w;
    while(~IO::scan_d(n),IO::scan_d(t),IO::scan_d(w))
    {
        init_t(t);
        ll ans = 0;
        int x,c;
        for(int i=0;i<n;i++) {
            scanf("%d%d",&x,&c);
            ans = ( ans + (ll)arr[abs(x-w)] * c % mod ) % mod;
        }
        IO::println(ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值