Newcoder 148 H.Rikka with Ants(计算几何+递归)

Description

二维平面上有两只蚂蚁初始在(1,0)(1,0)(1,0)点,有三条直线:

1.y=01.y=01.y=0,没有蚂蚁可以越过这条线

2.y=abx(a,b>0)2.y=\frac{a}{b}x(a,b>0)2.y=bax(a,b>0),只有第二只蚂蚁可以越过这条线

3.y=cdx(c,d>0)3.y=\frac{c}{d}x(c,d>0)3.y=dcx(c,d>0),只有第一只蚂蚁可以越过这条线

注意到蚂蚁只能往上走和往右走,且如果蚂蚁可以往上走就先往上走,不能往上走了再往右走,故两只蚂蚁的路径唯一,问被两只蚂蚁均经过的整点个数

Input

第一行一整数TTT表示用例组数,每组用例输入四个整数a,b,c,da,b,c,da,b,c,d

(1≤T≤105,1≤a,b,c,d≤109)(1\le T\le 10^5,1\le a,b,c,d\le 10^9)(1T105,1a,b,c,d109)

Output

如果两只蚂蚁均经过的整点有无限个则输出−1-11,否则输出整点个数,结果模998244353998244353998244353

Sample Input

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

Sample Output

-1
2
1
5049
3

Solution

显然若两条直线重合则两只蚂蚁均经过的整点有无穷个,假设ab>cd\frac{a}{b}>\frac{c}{d}ba>dc,两只蚂蚁若都经过(x,y)(x,y)(x,y)点,那么蚂蚁要么从(x,y−1)(x,y-1)(x,y1)往上走到达(x,y)(x,y)(x,y)点,要么从(x−1,y)(x-1,y)(x1,y)点无法到达(x−1,y+1)(x-1,y+1)(x1,y+1)点只能往右走到达(x,y)(x,y)(x,y)点,故有
{y≤abxy≤cdxy+1>ab(x−1)y+1>cd(x−1) \left\{ \begin{array}{lcl} y\le \frac{a}{b}x\\ y\le \frac{c}{d}x\\ y+1>\frac{a}{b}(x-1)\\ y+1>\frac{c}{d}(x-1)\\ \end{array} \right. ybaxydcxy+1>ba(x1)y+1>dc(x1)
ab>cd\frac{a}{b}>\frac{c}{d}ba>dc知只需满足2,32,32,3式即可,问题转化为求y=cdxy=\frac{c}{d}xy=dcxy+1=ab(x−1)y+1=\frac{a}{b}(x-1)y+1=ba(x1)xxx轴围成三角形中整点的个数(不包括原点以及y+1=ab(x−1)y+1=\frac{a}{b}(x-1)y+1=ba(x1)上的整点),这显然是有穷个点,假设两条直线内整点横坐标最大值为XXX,则轻易得到
X=⌊(a+b)dad−bc⌋ X=\lfloor\frac{(a+b)d}{ad-bc}\rfloor X=adbc(a+b)d
那么我们只要求出y=cdxy=\frac{c}{d}xy=dcxx∈[1,X]x\in [1,X]x[1,X]范围内与xxx轴围成整点的个数,再减去y+1=ab(x−1)y+1=\frac{a}{b}(x-1)y+1=ba(x1)x∈[1,X]x\in [1,X]x[1,X]范围内与xxx轴围成的纵坐标非负的整点个数即为答案

对于第一部分,显然有
X+∑x=1X⌊cxd⌋ X+\sum\limits_{x=1}^X\lfloor\frac{cx}{d}\rfloor X+x=1Xdcx
对于第二部分,先把直线向左平移一个单位,然后想上平移一个答案,则第二部分答案等价于y=abxy=\frac{a}{b}xy=baxx∈[0,X−1]x\in [0,X-1]x[0,X1]范围内与xxx轴围成的纵坐标为正的整点个数,也即为
∑x=0X−1⌊axb⌋ \sum\limits_{x=0}^{X-1}\lfloor\frac{ax}{b}\rfloor x=0X1bax
f(a,b,c,n)=∑x=0n⌊ax+bc⌋f(a,b,c,n)=\sum\limits_{x=0}^n\lfloor\frac{ax+b}{c}\rfloorf(a,b,c,n)=x=0ncax+b,则所求答案为X+f(c,0,d,X)−f(a,0,b,X−1)X+f(c,0,d,X)-f(a,0,b,X-1)X+f(c,0,d,X)f(a,0,b,X1),只要求出fff即可

1.若a=0a=0a=0,则显然f(a,b,c,n)=(n+1)⋅⌊bc⌋f(a,b,c,n)=(n+1)\cdot \lfloor\frac{b}{c}\rfloorf(a,b,c,n)=(n+1)cb

2.若a,ba,ba,b不全小于ccc,那么把这个下取整的两块整数拿出来,也即
⌊ax+bc⌋=⌊ac⌋⋅x+⌊bc⌋+⌊(a%c)⋅x+b%cc⌋ \lfloor\frac{ax+b}{c}\rfloor=\lfloor\frac{a}{c}\rfloor \cdot x+\lfloor\frac{b}{c}\rfloor+\lfloor\frac{(a\%c)\cdot x+b\%c}{c}\rfloor cax+b=cax+cb+c(a%c)x+b%c
进而有
f(a,b,c,n)=f(a%c,b%c,c,n)+n(n+1)2⋅⌊ac⌋+(n+1)⋅⌊bc⌋ f(a,b,c,n)=f(a\%c,b\%c,c,n)+\frac{n(n+1)}{2}\cdot \lfloor\frac{a}{c}\rfloor+(n+1)\cdot \lfloor\frac{b}{c}\rfloor f(a,b,c,n)=f(a%c,b%c,c,n)+2n(n+1)ca+(n+1)cb
3.若0&lt;a&lt;c,0≤b&lt;c0&lt;a&lt;c,0\le b&lt;c0<a<c,0b<c,回到该式的几何意义,即为直线y=ax+bcy=\frac{ax+b}{c}y=cax+bx∈[0,n]x\in [0,n]x[0,n]范围内与xxx轴围成的区域中纵坐标为正的整点个数,由于bc&lt;1\frac{b}{c}&lt;1cb<1,故该范围没有横坐标x=0x=0x=0的整点,记该区域整点纵坐标最大值为mmm,则有
m=⌊an+bc⌋ m=\lfloor\frac{an+b}{c}\rfloor m=can+b
对于[1,n]×[1,m][1,n]\times [1,m][1,n]×[1,m]范围内的nmnmnm个整点,不合法整点为直线y=ax+bcy=\frac{ax+b}{c}y=cax+byyy轴围成的、横坐标为正且不在直线上的整点,这些整点也即为y=ax+b−1cy=\frac{ax+b-1}{c}y=cax+b1yyy轴围成的横坐标为正的整点个数,交换两个坐标轴即为y=cx−b−1ay=\frac{cx-b-1}{a}y=acxb1xxx轴在x∈[1,m]x\in [1,m]x[1,m]范围内围成区域的纵坐标为正的整点个数,也即为f(c,c−b−1,a,m−1)f(c,c-b-1,a,m-1)f(c,cb1,a,m1),故此时有
f(a,b,c,n)=nm−f(c,c−b−1,a,m−1) f(a,b,c,n)=nm-f(c,c-b-1,a,m-1) f(a,b,c,n)=nmf(c,cb1,a,m1)
递归求解即可,注意在计算mmm时,ananan可能会爆long longlong\ longlong long,要用__int128\_\_int128__int128

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int128 lll;
#define mod 998244353
#define inv2 499122177 
int mul(int x,int y)
{
	ll z=1ll*x*y;
	return z-z/mod*mod;
}
int add(int x,int y)
{
	x+=y;
	if(x>=mod)x-=mod;
	return x;
}
int f(int a,int b,int c,ll n)
{
	if(a==0)return mul((n+1)%mod,b/c);
	if(a>=c||b>=c)
	{
		int res=mul(mul(mul(n%mod,(n+1)%mod),inv2),a/c);
		res=add(res,mul((n+1)%mod,b/c));
		return add(res,f(a%c,b%c,c,n));
	}
	ll m=((lll)a*n+b)/c;
	return add(mul(n%mod,m%mod),mod-f(c,c-b-1,a,m-1));
}
int main()
{
	int T,a,b,c,d;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d%d",&a,&b,&c,&d);
		if(1ll*a*d==1ll*b*c)
		{
			printf("-1\n");
			continue;
		}
		if(1ll*a*d<1ll*b*c)swap(a,c),swap(b,d);
		ll x=(1ll*(b+a)*d)/(1ll*a*d-1ll*b*c);
		int ans=add(add(x%mod,f(c,0,d,x)),mod-f(a,0,b,x-1));
		printf("%d\n",ans);
	} 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值