问题描述
引言
刚开始看见这题想直接暴力解,但是一看数据范围,10^14,绝对超时,翻了好多题解,看懂了这个解法,记录一下😊
思路
- 题目要求是找出 S<=余数<=T 的个数,而余数是连续的(0,1,2……)
- ∴可以考虑类似前缀和的方式,做减法:所有合法情况= <=T的情况 - <=(S-1)的情况
- 设求当前合法余数个数的函数为f(A,B,x): x是限制余数大小的变量
- ∴res=f(A,B,T)-f(A,B,S-1)
f 怎么考虑呢?
- 当x<0的时候:直接返回0
∵不可能出现余数是负数的情况 - b∈[1,B],通过枚举除数,确定当前的余数情况:
- 当 b<=x的时候,余数情况是:[0,b-1]<x,全部符合,所以这时候,被除数A不管是什么,都可以
∴res+=A - 当b>x的时候,这时余数会出现>x的情况,怎么考虑,举个例子:
当A=13,b=4,x=2的时候:
对A进行分块:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 |
可以发现只要可以整除一个b,就可以得到对应的余数,并且此时余数的范围是大于我们要求的,所以res+=(A//b)*(x+1)
为什么要+1?
∵ 当x=2 ,我们需要的余数有[0,1,2]三个,要把0出现的情况加上
∴要+1
同时也要考虑余数的情况,如上表,13%4=1,也符合
∴res+=min(A%b,x)
为什么要取最小?
∵因为这时有可能出现余数>x的错误情况,所以两个要取最小
eg:当A=9,b=5,x=2
此时res+=min(9%5,2)=2
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 0 | 1 | 2 | 3 | 4 |
为什么这时候不用+1了?
观察上表,能整除的情况是可整除段的最后一个,但是当前我们考虑的是取余后的余数情况,到不了被整除的0情况
∴不用+1了
综上所述,可得代码:
代码
import os
import sys
# 请在此输入您的代码 这直接暴力绝对是不行的
def f(A,B,x):
#合法的范围:[0,T]-[0,S-1]
if x<0:
return 0#不合法情况
res=0
for b in range(1,B+1):
if b<=x:
res+=A
else:
res+=(A//b)*(x+1)+min(x,A%b)
return res
A,B,S,T=list(map(int,input().split()))
print(f(A,B,T)-f(A,B,S-1))
ok,过了
—完结撒花—
记录一下解题过程,希望对大家有帮助,如果哪里有问题或者不足,请路过的朋友们帮忙指正一下~,感谢感谢!