0
点赞
收藏
分享

微信扫一扫

SDUT 3896 HEX 山东第八届ACM大赛D题(组合数学)


题目提交地址:http://www.sdutacm.org/onlinejudge2/index.php/Home/Index/problemdetail/pid/3896.html

HEX


Time Limit: 4000MS  Memory Limit: 131072KB


Submit  Statistic  Discuss


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;
}





举报

相关推荐

0 条评论