首先要进行一些特判:
当 m = 1 m=1 m=1 或 n = 1 n=1 n=1 或 m > n m>n m>n 时,结果为 0 0 0
当 m = n m=n m=n 或 m = n − 1 m=n-1 m=n−1 时,结果为 1 1 1
此时 2 ≤ m ≤ n − 2 2\le m\le n-2 2≤m≤n−2,对 i < j i
⌈ j i ⌉ = m \lceil\frac{j}{i}\rceil=m ⌈ij⌉=m
由于 ⌈ j i ⌉ = ⌊ j − 1 i ⌋ + 1 \lceil\dfrac{j}{i}\rceil=\lfloor\dfrac{j-1}{i}\rfloor+1 ⌈ij⌉=⌊ij−1⌋+1,因此上式等价于:
⌊ j − 1 i ⌋ + 1 = m \begin{aligned} \lfloor\dfrac{j-1}{i}\rfloor+1&=m\\ \end{aligned} ⌊ij−1⌋+1=m
再代入 i + j = n i+j=n i+j=n 得:
⌊ n − i − 1 i ⌋ + 1 = m ⌊ n − 1 i ⌋ = m ( 1 ) \begin{aligned} \lfloor\dfrac{n-i-1}{i}\rfloor+1&=m\\ \lfloor\dfrac{n-1}{i}\rfloor&=m\qquad (1)\\ \end{aligned} ⌊in−i−1⌋+1⌊in−1⌋=m=m(1)
因此转化为 i < j i
⌊ i j ⌋ = m − 1 ⌊ n − j j ⌋ = m − 1 ⌊ n j ⌋ = m ( 2 ) \begin{aligned} \lfloor\frac{i}{j}\rfloor&=m-1\\ \lfloor\frac{n-j}{j}\rfloor&=m-1\\ \lfloor\frac{n}{j}\rfloor&=m\qquad(2)\\ \end{aligned} ⌊ji⌋⌊jn−j⌋⌊jn⌋=m−1=m−1=m(2)
因此转化为 i > j i>j i>j 时,有多少个 j j j 满足式 ( 2 ) (2) (2)。
然后可以推出各自的范围:
i < j i
⌊ n − 1 i ⌋ = m m ≤ n − 1 i i ≤ n − 1 m i ≤ ⌊ n − 1 m ⌋ 因为 i 是整数 m > n − 1 i − 1 m + 1 > n − 1 i i > n − 1 m + 1 i ≥ ⌊ n − 1 m + 1 ⌋ + 1 \begin{aligned} \lfloor\frac{n-1}{i}\rfloor&=m\\ m&\le\frac{n-1}{i}\\ i&\le\frac{n-1}{m}\\ i&\le\lfloor\frac{n-1}{m}\rfloor\text{ 因为 $i$ 是整数}\\ m&>\frac{n-1}{i}-1\\ m+1&>\frac{n-1}{i}\\ i&>\frac{n-1}{m+1}\\ i&\ge\lfloor\frac{n-1}{m+1}\rfloor+1\\ \end{aligned} ⌊in−1⌋miimm+1ii=m≤in−1≤mn−1≤⌊mn−1⌋ 因为 i 是整数>in−1−1>in−1>m+1n−1≥⌊m+1n−1⌋+1
i ≥ j i\ge j i≥j 时:
⌊ n j ⌋ = m m ≤ n j j ≤ n m j ≤ ⌊ n m ⌋ m > n j − 1 m + 1 > n j j > n m + 1 j ≥ ⌊ n m + 1 ⌋ + 1 \begin{aligned} \lfloor\frac{n}{j}\rfloor&=m\\ m&\le\frac{n}{j}\\ j&\le\frac{n}{m}\\ j&\le\lfloor\frac{n}{m}\rfloor\\ m&>\frac{n}{j}-1\\ m+1&>\frac{n}{j}\\ j&>\frac{n}{m+1}\\ j&\ge\lfloor\frac{n}{m+1}\rfloor+1\\ \end{aligned} ⌊jn⌋mjjmm+1jj=m≤jn≤mn≤⌊mn⌋>jn−1>jn>m+1n≥⌊m+1n⌋+1
因此得到两个不等式组:
{ i ≤ ⌊ n − 1 m ⌋ i ≥ ⌊ n − 1 m + 1 ⌋ + 1 { j ≤ ⌊ n m ⌋ j ≥ ⌊ n m + 1 ⌋ + 1 \begin{aligned} &\begin{cases} i&\le\lfloor\dfrac{n-1}{m}\rfloor\\ i&\ge\lfloor\dfrac{n-1}{m+1}\rfloor+1\\ \end{cases}\\ &\begin{cases} j&\le\lfloor\dfrac{n}{m}\rfloor\\ j&\ge\lfloor\dfrac{n}{m+1}\rfloor+1\\ \end{cases} \end{aligned} ⎩⎪⎨⎪⎧ii≤⌊mn−1⌋≥⌊m+1n−1⌋+1⎩⎨⎧jj≤⌊mn⌋≥⌊m+1n⌋+1
因此最终的答案就是
⌊ n − 1 m ⌋ − ⌊ n − 1 m + 1 ⌋ + ⌊ n m ⌋ − ⌊ n m + 1 ⌋ \lfloor\dfrac{n-1}{m}\rfloor-\lfloor\dfrac{n-1}{m+1}\rfloor+\lfloor\dfrac{n}{m}\rfloor-\lfloor\dfrac{n}{m+1}\rfloor ⌊mn−1⌋−⌊m+1n−1⌋+⌊mn⌋−⌊m+1n⌋
代码如下:
#include
#include
using namespace std;
typedef long long ll;
int T;
ll n,m;
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&m);
ll res=0;
if(m==1||m>n||n==1)res=0;
else if(m==n||m==n-1)res=1;
else res=(n-1)/m-(n-1)/(m+1)+n/m-n/(m+1);
printf("%lld\n",res);
}
return 0;
}
当时我是用分块做的:
#include
#include
using namespace std;
typedef long long ll;
int T;
ll n,m;
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&m);
ll res=0;
if(m==1||m>n||n==1)res=0;
else if(m==n||m==n-1)res=1;
else{
//if(m==2&&(n%2==0))res++;
ll k;
ll i=(n-1)/(m+1);
for(;i<=(n-1)/2;i=k+1){
k=(n-1)/((n-1)/i);
if((n-1)/i==m){
res+=k-i+1;
break;
}
}
ll j=n/(m+1);
for(;j<=(n-1)/2;j=k+1){
k=n/(n/j);
if(n/j==m){
res+=k-j+1;
break;
}
}
}
printf("%lld\n",res);
}
return 0;
}