2017 ACM山东省赛 D - HEX 组合数学-数论

先把题面贴一下吧:

首先感谢青科大授权 SDUT-OJ 挂题~~~

省赛重现链接:2017 “浪潮杯”山东省第八届ACM大学生程序设计竞赛 重现


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
Hint
Author
“浪潮杯”山东省第八届ACM大学生程序设计竞赛(感谢青岛科技大学)

题目大意:

给出一个蜂窝状图,从(1,1)开始,每次可以移动一步,有左下、右下、下三个方向,给出指定坐标,问一共有多少种走法,答案对1e9+7取模。


这个题我们在现场赛的时候没有推出来,其实是和C题很像的,都是组合数学加上乘法逆元,可惜当时因为心态和时间问题,加上选题策略有问题,没有人仔细去推这个题。。。唉,都是泪。。。

回来后我在上课的时候推了一下就推出来了,确实和C题非常像,甚至只需要改改主逻辑就可以。。。


上解题思路:

 给出蜂窝的坐标(x,y),可以推算出两个数据:
1,最大步数,为x-1,即为全部左走或者右走的步数;
2,距离(1,1)的横向偏移量,为(x+1-2*y)(设左偏为正)。
利用这两个数据,即可推算出结果:
首先考虑全部左走或右走,即最大步数的情况,设左走为a,右走为b,下走为c,可得a+b=x-1,a-b=x+1-2*y,c=0,解出a和b,这部分的答案即为A(a+b+c,a+b+c)/(A(a,a)*A(b,b)*A(c,c));
然后考虑每一步下走相当于一次左走加一次右走,则每次a--,b--,c++,直到a,b其中一个或者全部为0,对于每次操作,可得结果也为A(a+b+c,a+b+c)/(A(a,a)*A(b,b)*A(c,c)),
累加结果即可,取模问题也是用乘上乘法逆元再取模的方法解决。。不会乘法逆元的可以先去学习一下。。。


最后上自己后来AC的代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL i,x,y,a,b,c,ans,p[112345],mod=1e9+7,n[112345];
LL exgcd(LL a,LL b,LL &x,LL &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	LL r=exgcd(b,a%b,x,y),temp=x;
	x=y,y=temp-a/b*y;
	return r;
}
LL cal(LL a,LL m){
	LL ans,x,y,gcd=exgcd(a,m,x,y);
	if(1%gcd)
		return -1;
	x*=1/gcd,m=abs(m),ans=x%m;
	if(ans<=0)
		ans+=m;
	return ans;
}
int main(){
	p[0]=1,n[0]=cal(p[0],mod);
	for(i=1;i<112345;i++)
		p[i]=(p[i-1]*i)%mod,n[i]=cal(p[i],mod);
	while(~scanf("%lld %lld",&x,&y)){
		ans=c=0,a=x-y,b=x-a-1;
		while(~a&&~b)
			ans=(ans+p[a+b+c]*n[a]%mod*n[b]%mod*n[c]%mod)%mod,a--,b--,c++;
		printf("%lld\n",ans);
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值