18th Zhejiang Provincial F. Fair Distribution 数论分块

37 篇文章 0 订阅
24 篇文章 0 订阅

Problem F
数论分块
话说正解是可以直接对m-1进行分块算值,然而自己没太理解,用了另一种分块方式。

题意

给你两个数 n , m ( n , m ≤ 1 e 8 ) n, m(n, m\leq1e8) n,m(n,m1e8), 你需要选择两个数 x , y ( x , y ≥ 0 , n − x > 0 ) x, y(x,y \geq 0, n-x>0) x,y(x,y0,nx>0), 使得 m + y m+y m+y n − x n-x nx 的倍数,请最小化 x + y x+y x+y

思路

首先如果 n ≥ m n\geq m nm ,可以直接得出答案为 n − m n-m nm,下考虑 n < m n<m n<m 的情况。
i = n − x i = n - x i=nx,对于每一个 i i i, 可以在 O ( 1 ) O(1) O(1) 内求出对应的 x + y x+y x+y,于是考虑暴力枚举 i ∈ [ 1 , n ] i\in [1, n] i[1,n], 可以在 O ( n ) O(n) O(n) 内得出答案。
可以用数论分块优化这一过程,对于 m i \frac{m}{i} im ,在 i ∈ [ l , r ] , 其 中 r = m / ( m / l ) i \in [l,r],其中r = m/(m/l) i[l,r]r=m/(m/l) 内的值是一样的。
先给出结论:答案即为 [ 1 , m ] [1,m] [1,m] 按上式数论分块过程中取到的所有 f ( l ) , f ( r ) f(l),f(r) f(l),f(r) 的最小值。 ( l , r ≤ n ) (l,r\leq n) (l,rn)
其中函数 f ( i ) f(i) f(i) 表示当 n n n 变为 i i i 时,对应的 x + y x+y x+y 值。不多赘述了,有问题可以看代码。
下面给出具体做法即简略证明:

  1. 举个例子,比如 n = 10 , m = 11 , l = 6 n = 10,m = 11,l=6 n=10,m=11,l=6, 在 i ∈ [ 6 , 10 ] i\in [6,10] i[6,10] 内, 10 i = 1 \frac{10}{i} = 1 i10=1,容易发现在这个区间内,只有 l l l 可能成为最终答案,为什么呢?就拿这个例子来说,对于 i ∈ [ 6 , 10 ] i\in [6, 10] i[6,10] ,它们的 y y y 依次为 1,3,5,7,9,而它们的 x x x 每次会少1,即 f ( i ) f(i) f(i) 是随 i i i 的增大而递增的,即 f ( l ) f(l) f(l) 是这个区间的最优解。
  2. y y y 不一定是单调递增的,比如把上例换为 m = 10 m=10 m=10 ,对于 i ∈ [ 6 , 10 ] i\in [6, 10] i[6,10] ,它们的 y y y 依次为 2,4,6,8,0,这也容易理解,因为 10 ∣ 10 10|10 1010,所以不需要*2-10,在这种情况下, r r r 可能取到这个区间的最小值。但 0 仅可能出现在分块的右端点,因为一旦出现 0,对于下一个 i i i, 它就在另一个块里了。 其实也好证明,但没必要,比如 5 ∣ 10 5|10 510,但10/5=2,而10/6=1 ,即 6 在下一个块里。

时间复杂度: 即分块的复杂度, O ( n ) O(\sqrt n) O(n )
有人可能要问 y y y 单增 x x x 单减为什么 f ( i ) f(i) f(i) 一定单增?,因为 x x x 每次一定减少1,而 y y y 每次增加的也至少为1,所以 f ( i ) f(i) f(i) 一定是单增的。

代码

int f(int x) {	//计算当n减小到x时,n和m变化之和
	int ans = (n - x) + (m+x-1)/x * x - m;
	return ans;
}
void solve() {
	cin >> n >> m;
	if(n >= m) {
		cout << n - m << endl;
		return;
	}
	int ans = INF;
	for(int l = 1, r; l <= n; l = r + 1) {
		ans = min(ans, f(l));
		r = min(n, m / (m / l));
		if(m % r == 0)
			ans = min(ans, f(r));
	}
	cout << ans << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值