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
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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪的期许

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值