51nod-1131: 覆盖数字的数量

【传送门:51nod-1131


简要题意:

  给出A,B,表示有一个区间为A到B

  给出X,Y,表示有一个区间为X到Y

  求出X到Y中能够被A到B中的数(可重复)相加得到的不同的数的个数


题解:

  乱搞题,暴力显然不行,但是我们会发现l到r中的数能被表示出来,那么k*l到k*r的数也能被表示出来(k为常数)

  其实这个性质很显然

  然后随着k的增大,最终得到的区间会重叠

  如样例中A=8,B=10

  (8 10)->(16 20)->(24 30)->(32 40)->(40 50)....

  会发现当k=4时,k*A=32,k*B=40,然后k再加1的时候,区间重叠了

  一旦重叠,那就说明当k>=4时,32及以上的数都能被表示出来

  所以我们就可以乱搞了,因为分界的k满足k*B>=(k+1)A,所以我们可以得到k=A/(B-A),然后分情况就好了


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL A,B,X,Y;
        scanf("%lld%lld%lld%lld",&A,&B,&X,&Y);
        if(A>Y){printf("0\n");continue;}
        if(A>X) X=A;
        LL k=A/(B-A);
        if(k==0||k==1){printf("%lld\n",max(0LL,Y-max(X,A)+1));continue;}
        LL sum=0;
        LL l,r,ans1,ans2,mid;
        l=1;r=k;ans1=-1;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(A*mid<=X) l=mid+1,ans1=mid;
            else r=mid-1;
        }
        l=1;r=k;ans2=-1;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(A*mid<=Y) l=mid+1,ans2=mid;
            else r=mid-1;
        }
        LL s=0;
        if(ans2==-1);
        else if(ans2<k)
        {
            if(X<=ans1*B) s+=ans1*B-X+1;
            if(Y<=ans2*B) s+=Y-ans2*A+1;
            if(ans1+1<ans2) s+=(ans2-ans1-1)*(B-A+1);
        }
        else
        {
            if(ans1<k)
            {
                LL s=Y-ans2*A+1;
                if(X<=ans1*B) s+=ans1*B-X+1;
                s+=(ans2-ans1-1)*(B-A+1);
            }
            else s=Y-X+1;
        }
        printf("%lld\n",s);
    }
    return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/Never-mind/p/9751494.html