CF724C Ray Tracing 扩展欧几里得 平面展开

LINK:Ray Tracing

虚这道题很久了 模拟赛考了一个加强版的 瞬间就想到了这道简化版的。

考虑做法 暴力模拟可能可以 官方正解好像就是这个。

不过遇到这种平面问题可以考虑把平面给无限的展开。

考虑展开之后点的坐标的通项 2kn +/- x 2km +/- y.

这个可以画图发现 那么就可以得到4个方程。

暴力解开 考虑遇到四个角就停止的问题 那么这个值必须要小于LCM(n,m).

显然 同时要保证合法的话需要>0.

容易发现方程只需要解一次 所以复杂度为 k+logn.

(真是ex死我了

ll n,m,k;
ll lcm,g,maxx;
ll xx,yy,ww;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline void exgcd(ll a,ll b)
{
	if(!b){xx=1,yy=0;ww=a;return;}
	exgcd(b,a%b);
	ll z=xx;xx=yy;yy=z-a/b*yy;
	return;
}
inline ll solve(ll x,ll y)
{
	ll c=y-x;
	if(c%ww)return -1;
	ll b=-m/ww;
	c/=ww;b=abs(b);
	ll w1=(xx*c%b+b)%b;
	ll ans=n*w1+x;
	return ans<=0||ans>=lcm?-1:ans;
}
signed main()
{
	freopen("1.in","r",stdin);
	n=read();m=read();k=read();
	g=gcd(n,m);lcm=n*m/g;
    n=n*2;m=m*2;
	exgcd(n,-m);
	for(ll i=1;i<=k;++i)
	{
		ll w,x,y;maxx=INF;
		x=read();y=read();
		if(!x&&!y){printf("0\n");continue;}
		w=solve(x,y);if(w!=-1)maxx=min(maxx,w);
		w=solve(x,-y);if(w!=-1)maxx=min(maxx,w);
		w=solve(-x,y);if(w!=-1)maxx=min(maxx,w);
		w=solve(-x,-y);if(w!=-1)maxx=min(maxx,w);
		printf("%lld\n",maxx==INF?-1:maxx);
	}
	return 0;
}
posted @ 2020-06-01 20:15  chdy  阅读(186)  评论(0编辑  收藏  举报