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,然后就可以转换成最后不要忘了,每个都带个-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";
}
}