http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1132
题意是给定a,b,l,r求[l,r]内有几个整数可以表示成ax+by(x,y为非负整数)。
直接算l<=ax+by<=r会重复计算一个数的多种表示方法,而两种表示方法(x,y)总是相差k*(b,-a),因此限制y取最小值进行去重
即x>=0,y>=0,l<=ax+by<=r,y<a/gcd(a,b)五个半平面的交的整点个数,可以分类一下然后用类欧几里德算法计算。
#include<stdio.h> typedef __int128 i64; i64 f(i64 a,i64 b,i64 c,i64 n){ if(!a||n<0)return 0; i64 s=0; if(a>=c)s+=a/c*(n+1)*n/2,a%=c; if(b>=c)s+=b/c*(n+1),b%=c; i64 m=(a*n+b)/c; return s+n*m-f(c,c-b-1,a,m-1); } i64 gcd(i64 a,i64 b){ for(i64 c;b;c=a,a=b,b=c%b); return a; } i64 g(i64 a,i64 b,i64 c){ c+=b; return f(a,c%a,b,c/a); } i64 cal(i64 a,i64 b,i64 c){ i64 z=a/gcd(a,b)-1; if(b*z>c)return g(a,b,c); i64 p=(c-b*z)/a+1; return p*(z+1)+g(a,b,c-a*p); } int main(){ int T; long long a,b,x,y; for(scanf("%d",&T);T;--T){ scanf("%lld%lld%lld%lld",&a,&b,&x,&y); i64 ans=cal(a,b,y)-cal(a,b,x-1); int ss[100],sp=0; do ss[++sp]=ans%10+48;while(ans/=10); while(sp)putchar(ss[sp--]); putchar(10); } return 0; }
时间: 2024-10-10 22:21:04