ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

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/gcd(a,b),-a/gcd(a,b)),因此可以限制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;
}
View Code

 

posted on 2017-08-18 12:47  nul  阅读(264)  评论(0编辑  收藏  举报