山东省第八届acm省赛 HEX
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
“浪潮杯”山东省第八届ACM大学生程序设计竞赛(感谢青岛科技大学)
思路:当初做这道题的时候的想法 是以(1.1)点往下延伸一个等腰三角形 以(x.y)点向上延伸一个倒着的等腰三角形,假设两个三角形相等 延伸的时候底边会相遇 当底边相遇时对这两个三角形合成的图形沿着等腰三角形的腰进行切割 切割出一个平行四边形 所有的从(1.1)到(x.y)的路线变都包括在这个平行四边形中。后来发现这个思路依然无法更进一步的求解,便放弃了 后来通道一种 将左移右移下移具体化的办法。由题可知,在一个位置上的移动方法无非左移、右移、下移 通过图像来看可以看出来左移位置坐标+(1.0) 右移位置坐标+(1.1) 下移坐标+(2.1) 然后可以看成起点(1.1)经过若干的左移、右移、下移变换到目标点(x.y) 可列 (1.1)+l*(1.0)+r*(2.1)=(x.y) 横纵坐标单独来看 1+l+2d=x;
1+r+d=y; 变换为 r+d=y-1,l+d=x-y; 两个公式 三个未知数,我们可以通过以d为枚举,每一个d都对应着一组l r d 即一种前往目的地左移 右移 下移的个数 而这些个数又可以根据组合数学进行排列 即着一种总的排列数个数 公式 c(l+r+d.l)*c(l+r+d.r)*c(l+r+d.d) 然后所有个数情况的和也就是最后总得个数,因为数据太大会爆数,所以求每一组的个数的时候可以先取模或者用卢卡斯定理来简化数据,防止re。
百度上还有一种方法 是先只考虑从出发点经左移和右移到达目标点 然后再把一个左移和一个右移变成一个下移
百度的详细解法:
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)),
累加结果即可,取模问题也是用乘上乘法逆元再取模的方法解决。。不会乘法逆元的可以先去学习一下。。。
- #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;
- }