【传送门: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 ");continue;} if(A>X) X=A; LL k=A/(B-A); if(k==0||k==1){printf("%lld ",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 ",s); } return 0; }