Rikka with Ants(类扩展欧几里得)

Rikka with Ants

Rikka with Ants (nowcoder.com)

题意:

给你两只蚂蚁,他们的起始坐标都为(1,0),然后每只蚂蚁都不能走到y=0下面,每只蚂蚁只能,向上或者向右走,并且必须尽量离对应的直线更近,一只蚂蚁不呢超过y=a/bx这条线,另一只蚂蚁不能超过y=c/dx这条线,问最后两只蚂蚁都能共同到达的点的个数,如果有无数个输出-1.

思路:

首先想象一下如何让他尽量靠近y=kx这条线段。其实就是当前再向上走一下就超过了该线段,所以要向右走,所以此时这两个的y是一样的,所以就是上一个的y再向上走一下就超过了k(x-1)这个线,所以就是(y+1)>k(x-1),所以每个蚂蚁满足y<kx,y+1<k(x-1);

首先蚂蚁的路径,假设第一只蚂蚁标记为l蚂蚁,另一只为r蚂蚁,所以

l蚂蚁满足:1:y<=a/bx

                    2:(y+1)>a/b*(x-1)

r蚂蚁满足:1:y<=c/dx

                    2:(y+1)>c/d*(x-1) 

我们可以利用这四个直线锁定一个区域,这个区域里的所有整数点个数就是我们想要的答案。

最后问题变成了最后锁定的区间,x=的最大值,四个方程联立后,得到的xmax=(a+b)*d/(a*d-b*c),l这里我们令n=xmax,所以也就是1~n,然后就可以转换成\sum_{i=0}^{n-1} \left \lfloor \frac{c*i}{d}\right \rfloor最后不要忘了,每个都带个-1,一共有n项,所以要加n。这里有个坑点,n的范围是10^18,a的范围是10^9,然而他需要让n*a,所以会爆long long,需要开__128.

AC代码:

#include<bits/stdc++.h>
#define lmw ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
#define lll __int128
#define ll long long
const ll mod=998244353;
ll ksm(ll x,ll y){
	ll res=1;
	while(y){
		if(y&1) res=res*x%mod;
		x=x*x%mod;
		y/=2;
	}
	return res%mod;
}
ll cal(ll a,ll b,ll c,ll n){
	ll ans=0;
	if(a==0){
		return b/c*(n+1)%mod;
	}
	if(a>=c||b>=c){
		ans=(ans+n*(n+1)/2*(a/c)%mod+(n+1)*(b/c)%mod)%mod;
		return (ans+cal(a%c,b%c,c,n))%mod;
	}
	ll m=((lll)a*n+b)/c;
	ans=n*m%mod;
	return ((ans-cal(c,c-b-1,a,m-1))%mod+mod)%mod;
}
signed main(){
    lmw;
	ll t;
	cin>>t;
	while(t--){
		ll a,b,c,d;
		cin>>a>>b>>c>>d;
		if(a*d==b*c){
			cout<<"-1\n";
			continue;
		}
		if(a*d>b*c){
			swap(a,c);
			swap(b,d);
		}
		ll op=((c+d)*b)/(c*b-a*d)-1;
		ll ans=cal(a,a,b,op)-cal(c,0,d,op);
		ans%=mod;
		ans+=op+1;
		ans%=mod;
		cout<<(ans+mod)%mod<<"\n";
	}	
}
 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值