砍树
不得不说也是挺神仙的一道题。
给了我一个教训,就是实在没思路的时候,不妨把题目中的东西写成数学式子,没准就会发现一些东西。
首先我考场上就\(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 ;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号