牛客网暑期ACM多校训练营(第十场): H. Rikka with Ants(类欧几里得)

链接:https://ac.nowcoder.com/acm/contest/148/H
来源:牛客网
 

题目描述

There are two small ants on Rikka's desk. If we consider Rikka's desk as a two-dimensional Cartesian coordinate system, both of them have coordinate (1,0).

Now, Rikka places three obstacles on her desk:
1. y = 0, none of the two ants can walk cross this line.
2. , only the second ant can walk cross this line.
3.  , only the first ant can walk cross this line.

It's remarkable that it is allowed for the ants to stand exactly on the obstacles. For example, if a=b=c=d=1, then both of the ants can reach (1,0),(1,1),(2,1),(2,2) and none of them can reach (1,2),(2,3).

Now, the ants start to move. Their strategy is very simple: In each second, let (x,y) be the current coordinate of one ant, if it can reach (x,y+1), it will walk to this point, otherwise it will walk to (x+1,y).(Since , if the ant can reach (x,y), it can also reach (x+1,y)).

The following image shows the first ant's path when a=3,b=2:


Now, given a,b,c,d, let p1 be the first ant's path and p2 be the second ant's path. Rikka wants you to calculate the number of the points with integer coordinates which are on both p1 and p2.

输入描述:

The first line contains a single integer t(1 ≤ t ≤ 105), the number of the testcases.

For each testcase, the first line contains four integers a,b,c,d(1 ≤ a,b,c,d ≤ 109).

输出描述:

For each testcase, output a single line with a single number, the answer modulo 998244353. If p1,p2 have infinite many common points, output -1.

输入

5
1 1 1 1
1 2 1 1
1 3 2 1
1 100 1 99
12 34 56 78

输出

-1
2
1
5049
3

 

题意:

有一条以原点为起点向第一象限的射线y=ax/b,蚂蚁A一开始在(1,0),它会按照以下规则行进:

  • 当前如果能往上走就往上走一格,否则就往右走一格
  • 不能越过射线y=ax/b

还有一条以原点为起点向第一象限的的射线y=cx/d,另一只蚂蚁B一开始也在(1,0),且它的行走规则也和A一样,不过它不能越过的射线是y=cx/d

问有多少个整数格点两个蚂蚁都会经过?如果有无数个输出-1

 

路:

我们假设a/b<c/d

因为蚂蚁A必须在直线a/b的下方(可在直线上),所以有:\small y\leqslant \tfrac{ax}{b}

又因为只要能往上就尽可能往上走,所以蚂蚁B当前位置的左上方必须在直线c/d上方,那么有\small y>\tfrac{c(x-1)}{d}-1

这样问题就变成了满足上面两个方程的整数格点个数,如果有无限个输出-1

 

然后这个问题就可以用类欧几里得解决了:设a/b = 1/3,c/d = 1/2情况如下:

可以看出,答案就是右图中红点的个数(除掉原点,因为起点是(1,0)),求出它们交点的横坐标 \small x=\tfrac{b*c+b*d}{b*c-a*d}

\small Ans=f(a,0,b,x)-f(c,0,d,x-1)+x

 

//https://ac.nowcoder.com/acm/contest/148/H
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<assert.h>
#include<iostream>
using namespace std;
#define LL long long
#define mod 998244353
#define er 499122177
LL F(LL a, LL b, LL c, LL n)
{
    LL sum;
	sum = (1+n)%mod*(n%mod)%mod*er%mod;
    if(a==0)
        return (n+1)%mod*((b/c)%mod)%mod;
    if(a>=c || b>=c)
        return (F(a%c, b%c, c, n)+sum%mod*((a/c)%mod)%mod+(n+1)%mod*((b/c)%mod)%mod)%mod;
    sum = ((__int128)a*n+b)/c;
    return (n%mod*(sum%mod)%mod-F(c, c-b-1, a, sum-1)+mod)%mod;
}
LL Gcd(LL x, LL y)
{
	if(y==0)
		return x;
	return Gcd(y, x%y);
}
int main(void)
{
	int T;
	LL a, b, c, d, n, temp;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
		temp = Gcd(a, b);
		a /= temp, b /= temp;
		temp = Gcd(c, d);
		c /= temp, d /= temp;
		if(a*d>b*c)
			swap(a, c), swap(b, d);
		if(a*d==b*c)
			printf("-1\n");
		else
		{
			n = (b*c+b*d)/(b*c-a*d);			//两条直线的交点
			printf("%lld\n", ((F(a, 0, b, n)-F(c, 0, d, n-1)+n%mod)%mod+mod)%mod);
		}
	}
	return 0;
}
/*
125
1000000000 1 1000000000 2
*/

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值