题解:
虽然之前做够扩展欧几米得的题,但是印象不深刻,但是今天做了这个题,就是一个应用它的题,看了很多题解,根本看不懂什么意思,看代码,也看不懂,最后在草稿本上再三推导,总算明白了所有的细节。
首先这道题可以直接转化为求ax+by=n+1的多少组解,如果直接枚举的,是不可能过OJ的,因此就要利用数论知识了。
首先将问题转为求ax+by=1的最小x,用exgcd求不解释了,求出最小x和最大公约数d,进而也可以求出最小公倍数c。
接下来问题的核心就是转化为ax+by=n+1时的最小x,首先预处理,如果d!=1,那么这个等式是可以化简的,所以设s=a/d,r=b/d,t=(n+1)/d,当然如果d==1,也有必要这样写。然后就是将ax+by==1的等式右边乘以t,相应的左边的若干组解当中的x,y也要乘以t。如此就是求他的最小x了,又由于在一个最简二元一次方程中,在坐标中根据画图可以得知,是线性的,x的变化量为b,y的变化量为a。因此根据已知的x*t,求x = x*t%r,得出的x就是ax+by=n+1时的最小x,如果x小于0就加上r。所以答案就是就是1+(n-x)/b,减去起始点,后面的距离都是线性的,所以x可以增长多少b就有多少组解了,当然要找到起始的x,因为起始x距离0不一定是d。
还是自己不能活用的自己的知识,回头看就是个简单的模板题+线性方程的处理。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <queue>
#define ll long long
const int MOD = 1e9+7;
#define CLR(a, b) memset((a), (b),sizeof((a)))
using namespace std;
ll exgcd(ll a, ll b, ll &d, ll &x, ll &y){
if (b == 0){
x=1;
y=0;
d=a;
}else{
exgcd(b, a%b, d, y, x);
y -= (a/b) * x;
}
}
int main(){
ll t, x, y, r;
cin >> t;
while(t--){
ll n, a, b, d;
cin >> n >> a >> b;
exgcd(a, b, d, x, y);
if((n+1)%d) {
cout<<"0"<<endl;
}else{
x = x*((n+1)/d);
r = b / d;
x = x % r;
while( x <= 0 )
x += r;
ll res = n - x * a;
if (res<0)
cout << '0' << "\n";
else
cout << 1 + res/((a*b)/d) << "\n";
}
}
}