题目提交地址:http://www.sdutacm.org/onlinejudge2/index.php/Home/Index/problemdetail/pid/3896.html
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
给出一个类似杨辉三角的菱形,求给定坐标的数值是多少。
不难看出,每一个位置的数字就是(左上,右上,正上)这三个数的和。
还有一个规律:每一个位置的数字即为(1,1)到该位置的路径条数。
【解析】:
根据红色字体的规律,可以用排列组合来做。
我们可以把这个菱形逆时针旋转45度,成为正方形,就容易看了。
从(1,1)点往(x,y)走。
下面依然以菱形图讲解,正方形辅助思考。
每一个位置(x,y),可以从(左上,上,右上)三个位置而来。回溯到(1,1)。
必定有若干条左路 l,若干条右路 r,和若干条上路c。
l 和 r 的获取:就是菱形图当前位置到当前行的左端的距离,和到右端的距离。可以借助正方形图考虑一下。
注意:一条上路,可以顶替 一条左上 加 一条右上。
对于给出的点(x,y)
1、假设上路不走,只走左上和右上。那么 l + r 就是走过的边的数量
对这 l+r 条路全排列,再除以 l 的全排列,除以 r 的全排列(高中知识)
就得到了当前情况从(1,1)到(x,y)的路数。
2、假设走 1 条上路,就会少走一条左上,少走一条右上。
总路数为 l-1 + r-1 + c ,求其全排列,再除以l,r,c的全排列
就得到了当前情况从(1,1)到(x,y)的路数。
3、仿照情况2,再增加一条上路,即c++;同时 l-- , r--;
重复此步骤,直到 l 和 r 有一个到了0;
注意此题数据量过大,全排列过程又涉及到除法,关键是发生了模除1e9+7,所以需要用乘法逆元来处理。
【代码】:
#include<stdio.h>
typedef long long ll;
const ll mod=1e9+7;
ll inv(ll b)//b的逆元
{
if(b<=1)return 1;
return (mod-mod/b)*inv(mod%b)%mod;
}
int main()
{
int x,y;
ll fac[101010]={1};
ll Inv[101010]={1,1};
for(int i=1;i<100101;i++)//打表
{
fac[i]=(fac[i-1]*i)%mod;//i的阶乘
Inv[i]=inv(fac[i]);//i的阶乘的逆元
}
while(~scanf("%d%d",&x,&y))
{
int right=x-y;
int left=x-1-right;
int c=0;//斜边
ll ans=0;
while(right>=0&&left>=0)//所有组合方式
{
ll sum=(((fac[left+right+c]*Inv[left])%mod*Inv[right])%mod*Inv[c])%mod;
ans=(ans+sum)%mod;
left--; right--; c++;
}
printf("%lld\n",ans);
}
return 0;
}