HEX
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
昨晚补了这个题,发现比赛的时候johsnows给我讲的是他的思路,不是题意,我以为那就是题意,赛后发现在赛时想了一个小时的题竟然还没懂题意。。。
题目的意思是说给你一个类似于蜂巢型的东西,每一次只能向左下,中间和右下走一步,给定你(x,y),问你走到(x,y)这个为位置有多少种情况。
我们一步步的来推,我们先定义(2,1)为第二行第一列,(3,2)为第三行第三列,现在我们假定给定的点是(5,2),那么这个位置相对于(1,1)来说向左偏移了两个单位,向下偏移了四个单位。现在我们有如下种走法:
左 右 中
3 1 0
2 0 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 long
using 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;
}