hihocoder1584 Bounce 2017icpc-北京赛区 扩展欧几里德

来源:互联网 发布:新建视图 sql语句 编辑:程序博客网 时间:2024/06/01 08:11

https://hihocoder.com/problemset/problem/1584

题意:在n*m的网格上,一颗小球左上方出发往右下的格子走,碰到边界就反弹,当小球到达角落就停止运动。求小球只经过一次的格子的数量。

题解:

第一步:如图(3*4为例),可以把每次反弹后的线路展开,每次反弹就增加m-1(碰到上下边界)或者n-1(碰到左右边界)。因为小球是45度方向,所以最后展开一定是正方形。于是可以列出不定方程(m-1)*x+m=(n-1)*y+n。其中x和y可以通过扩展欧几里德求出最小正数解(m-1)*x+m就是小球经过的格子总数(经过同一个两次的算两次)。

第二步:然后要减去经过两次的格子。x就是左右反弹次数之和,y就是上下反弹次数之和。相交的就是经过两次的要减去。可以从样例图的交点看出,数量就是x*y(结合样例图与反弹次数有关,因为每次反弹会与另一个方向的路线有相交)。

那么答案就是(m-1)*x+m-x*y。


画的有点丑。最后是要变成一个正方形。


样例图

代码:

#include<set>#include<map>#include<stack>#include<queue>#include<vector>#include<string>#include<bitset>#include<algorithm>#include<cstring>#include<cstdio>#include<cmath>#include<iomanip>#include<iostream>#define debug cout<<"aaa"<<endl#define mem(a,b) memset(a,b,sizeof(a))#define LL long long#define lson l,mid,root<<1#define rson mid+1,r,root<<1|1#define MIN_INT (-2147483647-1)#define MAX_INT 2147483647#define MAX_LL 9223372036854775807i64#define MIN_LL (-9223372036854775807i64-1)using namespace std;const int N = 100000 + 5;const int mod = 1000000000 + 7;//扩展欧几里德LL exgcd(LL a,LL b,LL &x,LL &y){if(b==0){x=1;y=0;return a;}LL r=exgcd(b,a%b,x,y);LL t=x;x=y;y=t-a/b*y;return r;} int main(){    int n,m;LL x,y,gcd,temp,num;while(~scanf("%d%d",&n,&m)){gcd=exgcd(m-1,1-n,x,y);x=x*(n-m)/gcd;temp=(1-n)/gcd;if(temp<0){temp=-temp;}//扩欧出来的解可能是负的,要求出最小正数解 if(x<0){x=x+(-x/temp+1)*temp;}else{x%=temp;}y=((m-1)*x+m-n)/(n-1);printf("%lld\n",(m-1)*x+m-x*y);}return 0;}


阅读全文
1 0
原创粉丝点击