欧几里得(炒鸡有趣的思维题)(提升思维能力)(阅读点赞的rp++++++)

欧几里得(炒鸡有趣的思维题)(提升思维能力)(阅读点赞的rp++++++)

其实这道题,emm,怎么说呢

没有什么特别的知识点

只是我觉得还蛮有意思

就发上来给大家看看

题意

今有一数轴, S S S 处有一颗棋子,要执行 N N N 次操作,每次操作中:

  1. 若棋子位置 ≥ T \ge T T ,向左移动 X X X
  2. 反之向右移动 Y Y Y

n n n 次操作后,棋子的位置。

T T T 组数据)

T ≤ 1 0 3 , N ≤ 1 0 18 , X , Y , ∣ S ∣ , ∣ T ∣ ≤ 1 0 18 T \le 10^3,N \le 10^{18},X,Y,|S|,|T| \le 10^{18} T103,N1018,X,Y,S,T1018

解法

首先,如果棋子只用往一边移动,那么直接特判输出

思考一下易得,如果有改变过方向,那么最后的落点一定在 [ t − x , t + y ) [t-x,t+y) [tx,t+y) 这段区间内1

处理一下,先把单个方向走的那部分搞定,这时候的 $ s $ 就在这个区间内,我们就可以进行操作啦

我们设往左走 a a a 步,那么往右走 n − a n-a na 步~~(废话,不然呢)~~

(不要怕未知数 a a a ,等会会化掉的)

那么最终的位置就是 s − a x + ( n − a ) y s-ax+(n-a)y sax+(na)y ,化简一下得到 s − a ( x + y ) + n y s-a(x+y)+ny sa(x+y)+ny

看回 [ t − x , t + y ) [t-x,t+y) [tx,t+y) 的区间,一共有 x + y x+y x+y 个元素

那么我们就把最终位置 % ( x + y ) \%(x+y) %(x+y) ,这样得到的数都是唯一的

a ( x + y ) % ( x + y ) = 0 a(x+y)\%(x+y)=0 a(x+y)%(x+y)=0

就可以化简成 ( s + n y ) % ( x + y ) (s+ny)\%(x+y) (s+ny)%(x+y)

再求出最左边(即 ( t − x ) % ( x + y ) (t-x)\%(x+y) (tx)%(x+y) 的值,就珂以以此为基准求出最终位置啦

Q:怎么求?

A:其实要分两种情况:(我们设 ( s + n y ) % ( x + y ) (s+ny)\%(x+y) (s+ny)%(x+y) 的值为 p p p ( t − x ) % ( x + y ) = q (t-x)\%(x+y)=q (tx)%(x+y)=q ,假设 x + y = 5 , p = 3 x+y=5,p=3 x+y=5,p=3

  1. q ≤ p q \le p qp ,例(取模后 [ t − x , x + y ) [t-x,x+y) [tx,x+y) 的值):

    1 , 2 , 3 , 4 , 0 1,2,3,4,0 1,2,3,4,0

    那么此时的 q = 1 q=1 q=1 ,答案即为 ( t − x ) + ( p − q ) (t-x)+(p-q) (tx)+(pq)

  2. q > p q>p q>p ,例:

    4 , 0 , 1 , 2 , 3 4,0,1,2,3 4,0,1,2,3

    此时 q = 1 q=1 q=1 ,那就不能直接减了,要把 q q q 加上模数 x + y x+y x+y ,所以答案为 $ (t-x)+(x+y)+(p-q)=(t+y)+(p-q)$

自我感觉代码蛮易懂的,还有不理解的可以再仔细看下(关键几行有注释)

而且很短诶!!!

删掉快读快输就那么一丁点

代码

#include<cstdio>
#define ll8 __int128
using namespace std;
ll8 rd()
{
	ll8 s1=0,s2=1;
	char t=getchar();
	while((t<'0')||(t>'9'))
	{
		t=getchar();
		if(t=='-')
		{
			s2=-1;
		}
	}
	while((t>='0')&&(t<='9'))
	{
		s1=(s1*10)+t-'0';
		t=getchar();
	}
	return s1*s2;
}
void wrt(ll8 x)
{
	if(x<0)
	{
		putchar('-');
		x=-x;
	}
	if(x>9)
	{
		wrt(x/10);
	}
	putchar(x%10+'0');
}
ll8 slv()
{
	ll8 n=rd(),s=rd(),t=rd(),x=rd(),y=rd();
	if((s-(n*x))>=t)
	{
		return s-(n*x);
	}
	if((s+(n*y))<=t)
	{
		return s+(n*y);
	}//特判掉不用转弯的情况
	if(s<(t-x))
	{
		ll8 tt=(t-s+y-1)/y;
		s+=tt*y;
		n-=tt;
	}
	if(s>=(t+y))
	{
		ll8 tt=(s-t+x-1)/x;
		s-=tt*x;
		n-=tt;
	}//处理掉单个方向走的部分
	ll8 p=(s+(n*y))%(x+y),q=(t+y)%(x+y);
	if(p>=q)
	{
		return t-x+p-q;
	}
	else
	{
		return t+y+p-q;
	}//分两种情况讨论
}
int main()
{
	int T;
	scanf("%d",&T);
	for(int i=1;i<=T;i++)
	{
		wrt(slv());
		putchar('\n');
	}
	return 0;
}

PS:本题要使用 __int128 ,不会用的读者可以借机了解下。

__int128 可以进行 +,-,*,/,% 五种运算,但是输入输出要用类似快读快输的方法。

后记

怎么样?是不是很好玩?

作者诚不欺你对吧?

那就点个赞吧

关注+收藏哦

谢谢🌷(今天送朵不一样的花)


  1. [ x , y ] [x,y] [x,y] 意为 x ∼ y x \sim y xy 的区间,包括 x , y x,y x,y ( x , y ) (x,y) (x,y) 意为不包括 x , y x,y x,y ↩︎

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值