[机房测试]Pay
Description
\(T\) 次询问,给定 \(a\)、\(b\) 和 \(c\),求出方程
\[ax+by=c
\]
的非负整数解的个数,并求出所有解的 \(x+y\) 的和。
Solution
有解的充要条件是 \(\gcd(a,b)|c\),用 \(exgcd\) 求出一组特解 \(x_0\) 和 \(y_0\) 后,就能得到通解
\[x=x_0+t\frac{b}{gcd}\\
y=y_0-t\frac{a}{gcd}
\]
所以可以得到 \(x\) 和 \(y\) 的下界,记 \(delx=\frac{b}{gcd}\) 和 \(dely=\frac{a}{gcd}\) 有
\[x_{min}=(x \bmod delx +delx)\bmod delx \\
y_{min}=(y \bmod dely +dely)\bmod dely
\]
根据这各自的差值,可以得到最大值
\[x_{max}=x_0+(y_0-y_{min})/dely*delx\\
y_{max}=y_0+(x_0-x_{min})/delx*dely
\]
方案数就是 \(x\) 的个数,和是一个等差数列,也容易求出。
#include<stdio.h>
#include<algorithm>
using namespace std;
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
typedef long long ll;
const int N=1e5+7;
const int Mod=1e9+7;
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b) return x=1,y=0,a;
ll ret=exgcd(b,a%b,y,x); y-=a/b*x;
return ret;
}
int T,opt;
void print(ll x,ll y){
printf("%lld",x);
if(opt==2) printf(" %lld",y);
putchar('\n');
}
int main(){
freopen("pay.in","r",stdin);
freopen("pay.out","w",stdout);
T=read(),opt=read();
while(T--){
ll a=read(),b=read(),c=read(),x,y;
ll Gcd=exgcd(a,b,x,y);
if(c%Gcd!=0){print(0,0);continue;}
x*=c/Gcd,y*=c/Gcd;
ll delx=abs(b/Gcd),dely=abs(a/Gcd);
ll minx=(x%delx+delx)%delx,miny=(y%dely+dely)%dely;
ll maxx=x+(y-miny)/dely*delx,maxy=y+(x-minx)/delx*dely;
if(minx>maxx||miny>maxy) print(0,0);
else{
ll ret=(maxx-minx)/delx+1;
print(ret,((maxx+minx)*ret/2)+((maxy+miny)*ret/2));
}
}
}