题目
题解
设横着每行放
x
x
x 个,竖着每排放
y
y
y 个,那么显然有一个柿子:
n
−
x
L
x
+
1
=
m
−
y
L
y
+
1
n
−
x
L
x
+
1
−
m
−
y
L
y
+
1
=
0
n
y
−
x
y
L
+
n
−
x
L
−
x
m
+
x
y
L
−
m
+
y
L
(
x
+
1
)
(
y
+
1
)
=
0
n
y
+
n
−
x
L
−
x
m
−
m
+
y
L
=
0
y
(
n
+
L
)
−
x
(
L
+
M
)
=
m
−
n
\begin{aligned} \frac {n-xL} {x+1}&=\frac {m-yL} {y+1}\\ \frac {n-xL} {x+1}-\frac {m-yL} {y+1}&=0\\ \frac {ny-xyL+n-xL-xm+xyL-m+yL} {(x+1)(y+1)}&=0\\ ny+n-xL-xm-m+yL&=0\\ y(n+L)-x(L+M)&=m-n\\ \end{aligned}
x+1n−xLx+1n−xL−y+1m−yL(x+1)(y+1)ny−xyL+n−xL−xm+xyL−m+yLny+n−xL−xm−m+yLy(n+L)−x(L+M)=y+1m−yL=0=0=0=m−n
设
a
=
−
m
−
L
,
b
=
L
+
m
a=-m-L,b=L+m
a=−m−L,b=L+m,那么有:
a
x
+
b
y
=
m
−
n
ax+by=m-n
ax+by=m−n
然后可以用扩展欧几里得算出一组特解 x 1 , y 1 x_1,y_1 x1,y1,设 g = gcd ( a , b ) g=\gcd(a,b) g=gcd(a,b),那么通解为 x = x 1 − k b g , y = y 1 + k a g x=x_1-k\frac b g,y=y_1+k\frac a g x=x1−kgb,y=y1+kga。
根据题目要求,有:
{
1
≤
x
≤
⌊
n
L
⌋
1
≤
y
≤
⌊
m
L
⌋
\begin{cases} 1\leq x \leq \lfloor \frac n L \rfloor\\ 1\leq y \leq \lfloor \frac m L \rfloor \end{cases}
{1≤x≤⌊Ln⌋1≤y≤⌊Lm⌋
那么我们可以将 x , y x,y x,y 带进去,大力算出 k k k 的取值范围。
具体来说我们需要分类讨论:
g>0 时
(避免理解出问题,这里还是要提一下,a显然小于0)
x 1 − k b g ≥ 1 k ≤ ⌊ x 1 − 1 b g ⌋ \begin{aligned} x_1-k\frac b g &\geq 1\\ k&\leq \lfloor \frac {x_1-1} {\frac b g} \rfloor \end{aligned} x1−kgbk≥1≤⌊gbx1−1⌋
x 1 − k b g ≤ ⌊ n L ⌋ − k b g ≤ ⌊ n L ⌋ − x 1 − k ≤ ⌊ ⌊ n L ⌋ − x 1 b g ⌋ k ≥ ⌈ x 1 − ⌊ n L ⌋ b g ⌉ \begin{aligned} x_1-k\frac b g &\leq \lfloor \frac n L \rfloor\\ -k\frac b g &\leq \lfloor \frac n L \rfloor-x_1\\ -k&\leq \lfloor \frac {\lfloor \frac n L \rfloor-x_1} {\frac b g} \rfloor\\ k&\geq \lceil \frac {x_1-\lfloor \frac n L \rfloor} {\frac b g} \rceil\\ \end{aligned} x1−kgb−kgb−kk≤⌊Ln⌋≤⌊Ln⌋−x1≤⌊gb⌊Ln⌋−x1⌋≥⌈gbx1−⌊Ln⌋⌉
y 1 + k a g ≥ 1 k ≤ ⌈ 1 − y 1 a g ⌉ \begin{aligned} y_1+k\frac a g &\geq 1\\ k&\leq \lceil \frac {1-y_1} {\frac a g } \rceil \end{aligned} y1+kgak≥1≤⌈ga1−y1⌉
y 1 + k a g ≤ ⌊ m L ⌋ k a g ≤ ⌊ m L ⌋ − y 1 k ≥ ⌊ ⌊ m L ⌋ − y 1 a g ⌋ \begin{aligned} y_1+k\frac a g&\leq \lfloor \frac m L \rfloor\\ k\frac a g&\leq \lfloor \frac m L \rfloor -y_1\\ k&\geq \lfloor \frac {\lfloor \frac m L \rfloor -y_1} {\frac a g} \rfloor\\ \end{aligned} y1+kgakgak≤⌊Lm⌋≤⌊Lm⌋−y1≥⌊ga⌊Lm⌋−y1⌋
这样就可以算出 k k k 的取值范围,假如左端点大于右端点,那么无解输出 0 0 0 即可。
g<0 时
将上面所有柿子的结果的符号取反即可。(即 ≤ \leq ≤ 变成 ≥ \geq ≥, ≥ \geq ≥ 变成 ≤ \leq ≤)。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define ll long long
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)return x=1,y=0,a;
ll re=exgcd(b,a%b,y,x);
return y-=a/b*x,re;
}
ll n,m,L;
ll x,y,a,b,g;
ll min_k,max_k;
int main()
{
scanf("%lld %lld %lld",&n,&m,&L);
a=-m-L;b=n+L;
g=exgcd(a,b,x,y);
if((m-n)%g)return printf("0"),0;
x*=(m-n)/g;y*=(m-n)/g;
if(g>0)
{
min_k=max( (ll)ceil((double)(m/L-y)/(a/g)) , (ll)ceil((double)(x-n/L)/(b/g)) );
max_k=min( (ll)floor((double)(x-1)/(b/g)) , (ll)floor((double)(1-y)/(a/g)) );
}
else
{
min_k=max( (ll)ceil((double)(x-1)/(b/g)) , (ll)ceil((double)(1-y)/(a/g)) );
max_k=min( (ll)floor((double)(x-n/L)/(b/g)) , (ll)floor((double)(m/L-y)/(a/g)) );
}
printf("%lld",max(max_k-min_k+1,0ll));
}