fireworks(杨辉三角+组合数学)

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大学生程序设计竞赛(感谢青岛科技大学)



参考https://blog.csdn.net/baidu_36227831/article/details/75948045


题目 大意


    有一种特殊的烟花,他每一秒可以向自己的左右两边分裂相同数量的烟花

    求所给位置在T时间后有多少个烟花

    要求输入n(烟花的数量),T(烟花的持续时间),w(所求的位置)

    接下来n行每一行输入两个数xi(烟花的初始位置)  ci(该点的烟花数量)



解题思路

  我们假设在0的位置有一个烟花

下面这个图给出了在1,2,3,秒时,各个坐标点产生的烟花的数量(蓝色为烟花数量)


仔细观察我们就可以发现这是一个我们很熟悉的数学定理,杨辉三角

                                 1

                              1    1

                           1    2   1

                         1  3     3  1

                       1 4    6   4  1

                     ……………………

有了这个之后就很好办了,只要能确定C(n,m)其中的n和m就可以了

在这里我们可以看出来n就是题目中给出的T,

要求m需要略作思考,这里我们设一个temp代表所求位置到烟花的绝对值,这里我们以图为例子推演一下,假设所求位置是-1,时间限制是3秒,烟花的初始位置是0,那么两点之间的绝对值temp=1,我们可以发现这里我们要求的m=(T/2)-(temp/2),或者是m=(T+1/2)-(temp+1/2),严格来说第二种是准确的,但是因为这道题目,T和temp只有是同奇同偶的情况下才代表该点有烟花(大家可以对着图演示一下就会发现这个规律),因为同奇同偶导致了两个式子结果是一样的。

上面提到了同奇同偶,但是怎么来确定同奇同偶?我这里是设了两个变量tomd(代表T的奇偶性),temp(所求到烟花的绝对值,这里只需要对temp%2与tmod判等就可以验证是否是同奇同偶)。

这个题用到的主要算法是逆元组合数,用来求组合数的还有lucas,但是而这还有有区别的,逆元求组合数适用于数较小且mod较大时,还要保证mod必须为素数,lucas适用于数较大且mod较小时的组合数

这两个算法这里不展开细讲,要想深入学习,可以看一下其他大牛的讲解


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define mod 1000000007
using namespace std;
const int N = 100000;
typedef long long LL;
LL fact[N+5],inv[N+5];
LL q_pow(LL x,LL y){
	LL ans=1;
	while(y){
		if(y&1) ans=ans*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ans;
}
void init(){
	fact[0]=1;
	for(int i=1;i<=N;i++)
	   fact[i]=fact[i-1]*i%mod;
	inv[N]=q_pow(fact[N],mod-2);
	for(int i=N-1;i>=0;i--){
		inv[i]=inv[i+1]*(i+1);
		inv[i]%=mod;
	}
}
LL C(int n,int m){
	return (fact[n]*inv[m]%mod)*inv[n-m]%mod;
}
int main(){
	init();
	int n,T,w;
	while(scanf("%d%d%d",&n,&T,&w)!=EOF){
		LL ans=0;
		LL tmod=T%2;
		for(int i=0;i<n;i++){
			int x,c;
			scanf("%d%d",&x,&c);
			LL temp=abs(x-w);
			if(temp%2==tmod&&temp<=T)
			   ans+=c*C(T,(T+1)/2-(temp+1)/2)%mod;
			ans%=mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值