Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) C. Ray Tracing

我不告诉你这个链接是什么

分析:模拟可以过,但是好烦啊。。不会写。还有一个扩展欧几里得的方法,见下:
假设光线没有反射,而是对应的感应器镜面对称了一下的话
不可描述
左下角红色的地方是原始的NM的方格,剩下的三个格子是镜面对称的结果。原来的点是(a,b)的话,剩下三个点从左上到右下分别是(a,2Nb),(2Ma,2Nb),(2Ma,b)。真实情况是一个点不止只有这三个镜像点,一个点可以在平面内生成无数个点,可以用坐标表示为(2Mk±a,2Nk±b)k为任意非负整数。
假设光线没有经过反射,那么用函数可以表示为y=x,这样要求包括镜像点在内的所有点x=y,于是就有二元一次方程2Mx±a=2Ny±b,可以改成四个二元一次方程式,用扩展欧几里得计算。
对于一个点,光线的真实情况是可能会经过多次,这意味着一个点以及它的镜像点可能有多个在y=x 上,这是就需要取最小的x坐标的点就行了。一个点也可能没有经过,扩展欧几里得无解就行了。还有需要注意的是如果光线经过了原来矩形框的三个角,那么光线就已经射出矩形框了,对于一些可以求出结果的点,还需要进行一下判断,真实情况下是否可行。

代码:

/*****************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define   offcin        ios::sync_with_stdio(false)
#define   sigma_size    26
#define   lson          l,m,v<<1
#define   rson          m+1,r,v<<1|1
#define   slch          v<<1
#define   srch          v<<1|1
#define   sgetmid       int m = (l+r)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   pb            push_back
#define   fi            first
#define   se            second

const int    INF    = 0x3f3f3f3f;
const LL     INFF   = 1e18;
const double pi     = acos(-1.0);
const double inf    = 1e18;
const double eps    = 1e-9;
const LL     mod    = 1e9+7;
const int    maxmat = 10;
const ull    BASE   = 31;

/*****************************************************/

//对于不定整数方程pa+qb=c,若 c mod Gcd(a, b)=0,则该方程存在整数解,否则不存在整数解
//p = p1 + b/Gcd(a, b) * t 
//q = q1 - a/Gcd(a, b) * t(其中t为任意整数,正负皆可)
LL exgcd(LL a,LL b,LL &x,LL &y) {
    if(!b) {x=1; y=0; return a; }
    LL r=exgcd(b,a%b,y,x);
    y-=a/b*x; 
    return r;
}

bool solve_equ(LL a,LL b,LL ca,LL cb,LL &x,LL &y,LL &d,LL &ans) {
    LL c = ca + cb;
    d = exgcd(a, b, x, y);
    if(c % d)  return false;
    LL k = c / d; LL g = b / d;
    if (g < 0) g = -g;
    g *= a; x *= k; y *= k;
    ans = a * x - cb;
    ans = (ans % g + g) % g;
    return true;
}

int main(int argc, char const *argv[]) {
    int N, M, K;
    cin>>N>>M>>K;
    LL over = INFF;
    for (int i = 0; i < 3; i ++) {
        LL a, b;
        if (i == 0) a = N, b = M;
        else if (i == 1) a = 0, b = M;
        else a = N, b = 0;
        LL x, y, d, res, ans = INFF;
        for (int k = 0; k < 4; k ++) {
            LL tmpa = a, tmpb = b;
            if (k & 1) tmpa = -tmpa;
            if ((k >> 1) & 1) tmpb = -tmpb;
            if (solve_equ(2 * M, -2 * N, tmpa, tmpb, x, y, d, res))
                ans = min(ans, res);
        }
        over = min(over, ans);
    }
    while (K --) {
        LL a, b;
        cin>>a>>b;
        LL ans = INFF, x, y, d, res;
        for (int k = 0; k < 4; k ++) {
            LL tmpa = a, tmpb = b;
            if (k & 1) tmpa = -tmpa;
            if ((k >> 1) & 1) tmpb = -tmpb;
            if (solve_equ(2 * M, -2 * N, tmpa, tmpb, x, y, d, res))
                ans = min(ans, res);
        }
        if (ans == INFF || (over != INFF && ans > over)) puts("-1");
        else cout<<ans<<endl;
    }
    return 0;
}

转载于:https://www.cnblogs.com/hahatianx/p/5943431.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值