数论
可能就我一个傻逼会坚持二分一直wa一个点还一直写下去吧….
不过还好的是最后发现问题症结:乘法爆long long 了…
改了一下__128秒过
不过感觉官方解确实比我想的简单一点
思路:
手玩一下,得到 a ∗ k 1 + b ∗ k 2 = n + 1 a*k1+b*k2=n+1 a∗k1+b∗k2=n+1这个不定方程,有约束条件 1 < = a ∗ k 1 < = n 1<=a*k1<=n 1<=a∗k1<=n,问题就转化为了在该约束下可行解的个数
先特判一下gcd(a,b)与n+1的关系,若无解则答案为0,接下来考虑有解情况
先exgcd得到特解k1’, 对于k1的通解我们则有 k 1 = k 1 ′ + b / g c d ( a , b ) ∗ t k1 = k1'+b/gcd(a,b)*t k1=k1′+b/gcd(a,b)∗t,t为任意整数
考察这个石子,单调递增,所以我们可以二分t,check函数自然就是检查约束条件是否满足
两次二分,分别得出t的左右边界,若如果在该区间内没有满足约束的解,答案则为0,否则答案即为区间长度
Code:
#include<bits/stdc++.h>
#define int __int128
#define rep(i,a,n) for(int i = a; i<=n; i++)
#define pb push_back
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int inf=2147483647;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void write(int x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int exgcd(int a,int b, int &x, int &y){
if(!b){
x = 1, y = 0;
return a;
}
else{
int d = exgcd(b,a%b,x,y);
int t = x;
x = y, y = t-(a/b)*y;
return d;
}
}
void solve(){
int n, a, b;
n=read(); a=read(); b=read();
int k1, k2;
int d=exgcd(a,b,k1,k2);
if((n+1)%d) {write(0);cout<<'\n';return;}
k1*=(n+1)/d;
k2*=(n+1)/d;
int l=-n, r=n;
int ansl=0, ansr=0;
while(l<=r){
int mid=(l+r)/2;
if(a*k1+a/d*b*mid>=1){
r=mid-1;
ansl=mid;
}
else l=mid+1;
}
l=-inf, r=inf;
while(l<=r){
int mid=(l+r)/2;
if(a*k1+a/d*b*mid<=n){
l=mid+1;
ansr=mid;
}
else r=mid-1;
}
if(a*k1+a/d*b*ansl>n||a*k1+a/d*b*ansr<1) {write(0);cout<<'\n';return;}
write(ansr-ansl+1);
cout<<'\n';
}
signed main(){
//ios;
int t=1;
t=read();
while(t--){
solve();
}
return 0;
}