【组合数】省赛CD题 SDUT_3895_fireworks SDUT_3896_HEX

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

/*
SDUT 3895
题意:
位于x的烟花炸开到x-1,x+1
有n个位置的烟花,问t秒后w位置的烟花数
比如index(位置)=3,c(数量)=2的烟花
会炸到index=2 c=2 和index=4 c=2

思路:
对于x位置的烟花,t秒后烟花的位置左边界为x-t,右边界为x+t
而且每隔2个单位都有烟花
就是x-t,x-t+2,x-t+4...x+t-2,x+t
别的位置肯定没有烟花
假设最开始的烟花数量为1,最后*c就好
还可以看出t秒后这些位置的烟花数量分别为
C(t,0) C(t,1) C(t,2)...
所以对于t秒后位于x位置c数量的烟花爆炸后,w位置有的烟花数是
c*C(t,k) k为第几个有烟花的位置
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL p=1e9+7;
LL f[100010];
LL quickpow(LL x,LL n)
{
    LL ans=1;
    while(n)
    {
        if(n&1)
            ans=ans*x%p;
        x=x*x%p;
        n>>=1;
    }
    return ans;
}
void Init()
{
    f[0]=1;
    for(int i=1; i<=1e5; i++)
        f[i]=f[i-1]*i%p;
}
LL C(LL n,LL m)
{
    return f[n]*(quickpow(f[n-m],p-2)*quickpow(f[m],p-2)%p)%p;
}
LL Lucas(LL n,LL m)
{
    if(m==0)
        return 1;
    return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}
int main()
{
    Init();
    LL n,t,w,x,c;
    while(~scanf("%lld%lld%lld",&n,&t,&w))
    {
        LL ans=0;
        while(n--)
        {
            scanf("%lld%lld",&x,&c);
            LL l=x-t;
            LL r=x+t;
            LL k=(w-l)/2;
            if((w-l)%2==1||w<l||w>r)
                continue;
            ans=(ans%p+c*Lucas(t,k)%p)%p;
        }
        printf("%lld\n",ans);
    }
    return 0;
}


HEX

Time Limit: 4000MS  Memory Limit: 131072KB
Problem Description

On a plain of hexagonal grid, we define a step as one move from the current grid to the lower/lower-left/lower-right grid. For example, we can move from (1,1) to (2,1), (2,2) or (3,2).

In the following graph we give a demonstrate of how this coordinate system works.

Your task is to calculate how many possible ways can you get to grid(A,B) from gird(1,1), where A and B represent the grid is on the B-th position of the A-th line.

Input

For each test case, two integers A (1<=A<=100000) and B (1<=B<=A) are given in a line, process till the end of file, the number of test cases is around 1200.

Output

For each case output one integer in a line, the number of ways to get to the destination MOD 1000000007.

Example Input
1 1
3 2
100000 100000
Example Output
1
3
1
Hint
Author
“浪潮杯”山东省第八届ACM大学生程序设计竞赛(感谢青岛科技大学)
/*
SDUT 3896
题意:
给定一个蜂窝形状的图片,
一个点可以向左向右向下走
问从(1,1)到(n,m)的路径有几种

思路:
假设不能往下走,在每个点可以选择向左向右走,
对位于(n,m)的点来说,
不管怎么走,她向左的步数一定是n-m,向右走的步数一定是m-1
总共步数是n-1,根据高中学的排列组合知识,
总路径数为C(n-1,m-1)就是说在这n-1步中选择m-1往右走
然后考虑能向下走的情况
一步向下走就相当于往左走一步再往右走一步
向下走一步,向左就少走一步,向右也少走一步
对于(n,m)点来说,它能向下走的最大步数是m-1
所以枚举向下走的步数c,
对每一个c
有路径数C(l+r+c,c)*C(l+r,l)*C(r,r)
就是先在总步数中选择c步向下走,然后在剩下的步数中选择l步往左走
*/
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const LL p=1e9+7;
LL f[200010],Inv[200010];
LL quickpow(LL x,LL n)
{
    LL ans=1;
    while(n)
    {
        if(n&1)
            ans=ans*x%p;
        x=x*x%p;
        n>>=1;
    }
    return ans;
}
void Init()
{
    f[0]=1;
    Inv[0]=1;
    for(int i=1; i<=200000; i++)
    {
        f[i]=f[i-1]*i%p;
        Inv[i]=quickpow(f[i],p-2)%p;
    }
}
LL C(LL n,LL m)
{
    if(n<m)
        return 0;
    return f[n]*(Inv[m]*Inv[n-m]%p)%p;
}
int main()
{
    Init();
    LL n,m;
    while(~scanf("%lld%lld",&n,&m))
    {
        LL l=n-m;
        LL r=m-1,ans=0;
        for(LL c=0; c<=m-1&&l>=0&&r>=0; c++)
        {
            ans=(ans+C(l+r+c,c)*C(l+r,l)%p)%p;
            l--;
            r--;
        }
        printf("%lld\n",ans);
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值