HEX----组合数+逆元+思维 山东省第八届省赛D题

来源:互联网 发布:mac开机进入客人用户 编辑:程序博客网 时间:2024/06/05 15:12

HEX

Time Limit: 4000MS Memory Limit: 131072KB
Submit Statistic

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 13 2100000 100000

Example Output

131

Hint

Author

“浪潮杯”山东省第八届ACM大学生程序设计竞赛(感谢青岛科技大学)
题目链接:http://www.sdutacm.org/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2081/pid/3896


昨晚补了这个题,发现比赛的时候johsnows给我讲的是他的思路,不是题意,我以为那就是题意,赛后发现在赛时想了一个小时的题竟然还没懂题意。。。


题目的意思是说给你一个类似于蜂巢型的东西,每一次只能向左下,中间和右下走一步,给定你(x,y),问你走到(x,y)这个为位置有多少种情况。


我们一步步的来推,我们先定义(2,1)为第二行第一列,(3,2)为第三行第三列,现在我们假定给定的点是(5,2),那么这个位置相对于(1,1)来说向左偏移了两个单位,向下偏移了四个单位。现在我们有如下种走法:

右 中

3 0

2 1

第一组示例代表着是左下走四步,右下走一步,第二组示例是说左下走两步,中间走一步。

拿第一组示例来说,我们会发现,一共走了四步,只要是往左下走三步,往右下走一步即可,并没有顺序关系,所以我们会得到第一种情况的走法C(3,4)*C(1,1)*C(0,0),同理,第二种情况就是C(2,3)*C(0,1)*C(1,1),所以总的走法就是两种情况的加和,所以我们枚举左下,中间,右下的其中一种,另外两个方向的步数就可以被计算出来,所以就出来了。

小提示:中间是直接往下移,所以中间可以算是先左下,后右下,所以从中间走一步顶两步。

上面的是wmn的做法,我本想这样敲,发现pbh有更简单的做法,思路差不多,就是一个正推,一个反推。

我们先计算出左右偏移量,然后我们会发现从(1,1)走到(x,y)的总方案数是A(a+b+c,a+b+c)(a代表左偏移量,b代表右偏移量,c代表从中间走的步数,我们只要走到这些步数就可以,然后计算顺序有多少种就可以了),然后我们会发现,走左边会有重复,中间和右边也是,所以我们减掉重复的步数A(a,a),A(b,b),A(c,c),所以最后结果就出来了,这个比较好敲,但是个逆向思维,算出总的,减掉重复的(怎么有种容斥的感觉)。

算左偏移量有个小技巧,假如输入(x,y),那么走的步数最多是x-1步((1,1)不用走),初始化的时候也就是说a+b==x-1,很巧妙的是左偏移量就是x-y,右偏移量就是x-1-a,中间就是0,仔细想想很容易就懂了。

记得把除法取膜换成乘逆元取膜,记得预处理。

代码:

#include <cstdio>#include <cstring>#include <iostream>#define LL long longusing namespace std;const int mod=1000000007;LL aa[200000];LL bb[200000];LL inv(LL t,LL p){    return t==1?1:(p-p/t)*inv(p%t,p)%p;}void Init(){    aa[0]=1;    bb[0]=1;    for(int i=1;i<=100000;i++){        aa[i]=(aa[i-1]*i)%mod;//(A(n,n))        bb[i]=inv(aa[i]%mod,mod);//(A(n,n)的逆元)    }}int main(){    int n,m;    Init();    while(~scanf("%d%d",&n,&m)){        int a=n-m,b=n-1-a;        int c=0;        int ans=0;        while(~a&&~b){            ans=(ans+(((aa[a+b+c]*bb[a]+mod)%mod*bb[b]+mod)%mod*bb[c]+mod)%mod)%mod;            a--,b--,c++;        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击