Loading

砍树

不得不说也是挺神仙的一道题。
给了我一个教训,就是实在没思路的时候,不妨把题目中的东西写成数学式子,没准就会发现一些东西。

首先我考场上就\(Hack\)了二分做法,然后没想到正解。

问题就是求一个最大的\(d\),满足

\[\sum(\lceil a_i/d \rceil*d-a_i)<=k \]

提出求和,移项

\[\sum\lceil a_i/d \rceil <= T , T = \lfloor\frac{(k + \sum a_i)}{d}\rfloor \]

然后可以知道,分子是定值,\(T,d\)的取值小于等于\(2*\sqrt{k+\sum a_i}\)种情况
这个挺好理解的,因为他最多就那么多广义因子(向下取整意义下的因子)

然后发现\(2*\sqrt{k+\sum a_i}\)可以全部都搜出来,那就搜出来,排个序。
倒序枚举,第一个满足上式的就是答案。

其实是数论分块,但是,想出来这个东西好像也不太需要数论分块的知识,还是自己太菜了,不要怪自己学的少。
求分块的时候也不用他给的啥结论啥的,直接根号枚举。
看看这个跟上一个相不相等,如果不想等就分一个新块,并且把他配套的广义因子也搞进去,最后排个序去个重就行了。(这个方法也适用与各种数论分块,如向上取整分块等)

\[\color\purple{\Huge{\text{把条件写成数学式子!!}}} \]

code

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define mp make_pair
#define R register int
#define int long long
#define printf Ruusupuu = printf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
typedef pair< int , int > PI ;
const int N = 9e5 + 10 ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

inline void wap( int &a , int &b ){ a = a ^ b , b = a ^ b , a = a ^ b ; }
inline int mins( int a , int b ){ int zt = b - a ; return a + ( zt & ( zt >> 31 ) ) ; }
inline int maxs( int a , int b ){ int zt = b - a ; return b - ( zt & ( zt >> 31 ) ) ; }
inline int abss( int a ){ int zt = a >> 31 ; return ( a + zt ) ^ zt ; }

int a [N] , n , k , sm , st [N] , top , res ; 

void sc(){
	n = read() , k = read() , sm = k ;
	for( R i = 1 ; i <= n ; i ++ ) a [i] = read() , sm += a [i] ;	
}

void work(){
	 int tops = sqrt( sm ) ;
	for( R i = 2 ; i <= tops + 1 ; i ++ ) 
		if( ( sm / i ) != ( sm / ( i - 1 ) ) ) st [++ top] = i - 1 , st [++ top] = sm / ( i - 1 ) ; 
	sort( st + 1 , st + 1 + top ) ; 
	top = unique( st + 1 , st + 1 + top ) - st - 1 ;
	
	for( R i = top ; i >= 1 ; i -- ){
		int ans = 0 ;
		for( R j = 1 ; j <= n ; j ++ ){
			int l = ( a [j] % st [i] == 0 ) ? a [j] / st [i] : ( a [j] / st [i] ) + 1 ;  
			ans += l ;
		} int u = sm / st [i] ;
		if( ans <= u ) printf( "%lld\n" , st [i] ) , exit( 0 ) ;
	} //printf( "%lld\n" , res ) ;
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
} 
posted @ 2021-06-27 20:37  Soresen  阅读(69)  评论(0)    收藏  举报