F. Fair Distribution


F. Fair Distribution

18界浙江省赛

1)题目大意:

有n个机器人和m个能量棒,每次操作可以杀掉一个机器人或者增加一个能量棒。问最少几次操作可以使得n'个机器人平分m'个能量棒。

2)思路:

暴力整数分块

暴力思路:枚举1到n每一个机器人的情况,算出第一个比b大的i的倍数,取min。

ll getceil(ll x , ll y){
	return x / y + (x % y ? 1 : 0) ;
}

ll solve(){

	ll a , b ;
	cin >> a >> b ;
	
	if(b % a == 0) return 0 ;
	if(a > b) return a - b ;
	ll ans = INF ;
	
	for(int i = 0 ; a - i > 0 ; i ++ ){//i是操作次数
		ll opBar = getceil(b , a - i) * (a - i) - b ;
		ans = min(ans , i + opBar) ;
	}
	return ans ;
}

枚举1到n一定会超时,所以采用整数分块

对于整除,x/y的答案是有块状的性质的(ceil和floor都有),所以我们对于某一块区间里的除数不用全部去操作,而是可以直接用端点来做。

ll getceil(ll x , ll y){//x/y向上取整的公式 
	return (x + y - 1) / y ;
}

ll solve(){

	ll a , b ;
	cin >> a >> b ;
	
	if(b % a == 0) return 0 ;
	if(a >= b) return a - b ;
	
	ll ans = INF ;

	for(ll l = 1 , r ; l <= a ; l = r + 1){ 
		r = (b - 1) / ((b  - 1) / l) ;//向下取整区间分块
		ans = min(ans , getceil(b , l) * l - b + a - l) ;
	}
	
	return ans ;
}
3)扩展和总结:

需要枚举n/i的答案时就可以用整数分块

复杂度2根n

向下取整的分块:

for (ll l = 1, r; l <= m; l = r + 1) {
    r = n / (n / l);  
}

向上取整的分块:

for(ll l = 1 , r ; l <= a ; l = r + 1){ 
		r = (b - 1) / ((b  - 1) / l) ;//向下取整区间分块
	}