51nod 种田 题解

题目

在这里插入图片描述

题解

设横着每行放 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+1nxLx+1nxLy+1myL(x+1)(y+1)nyxyL+nxLxm+xyLm+yLny+nxLxmm+yLy(n+L)x(L+M)=y+1myL=0=0=0=mn

a = − m − L , b = L + m a=-m-L,b=L+m a=mL,b=L+m,那么有:
a x + b y = m − n ax+by=m-n ax+by=mn

然后可以用扩展欧几里得算出一组特解 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=x1kgb,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} {1xLn1yLm

那么我们可以将 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} x1kgbk1gbx11


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} x1kgbkgbkkLnLnx1gbLnx1gbx1Ln


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+kgak1ga1y1


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+kgakgakLmLmy1gaLmy1


这样就可以算出 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));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值