[机房测试]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));
        }
    }
}
posted @ 2021-10-15 20:13  Kreap  阅读(31)  评论(0编辑  收藏  举报