这题卡常,别用long long
这题第一问好搞,直接二分答案
第二问,凡是看到求方案数并于组合数一定没有关系的一定用 Dp 解决!
然后定义状态,显然 表示前
个棍棍儿切了
刀的方案数
转移就是 ,
是满足条件的第一个点
然后我就不会优化了,看了题解,发现自己思维僵化竟然如此简单
然后可以用前缀和优化
要用滚动数组
// luogu-judger-enable-o2
# include <bits/stdc++.h>
const int N = 100000 + 5 ;
int sum [ N ] , pre [ 2 ] [ N ] , dp [ 2 ] [ N ] , L [ N ] , ans1 , ans2 ;
int to [ N ] , n , m , now , inf = 1e9 + 7 , mod = 10007 ;
bool check ( int lim ) {
int cnt = 0 , pre = 0 ;
for ( int i = 1 ; i <= n ; i ++ ) {
if ( L [ i ] > lim ) return false ;
if ( sum [ i ] - sum [ pre ] > lim )
pre = i - 1 , cnt ++ ;
}
return cnt <= m ;
}
int divx ( int l , int r ) {
int ans ;
while ( l <= r ) {
int mid = l + r >> 1 ;
if ( check ( mid ) ) r = mid - 1 , ans = mid ;
else l = mid + 1 ;
}
return ans ;
}
int main ( ) {
scanf ( "%d%d" , & n , & m ) ;
for ( int i = 1 ; i <= n ; i ++ )
scanf ( "%d" , & L [ i ] ) , sum [ i ] = sum [ i - 1 ] + L [ i ] ;
ans1 = divx ( 1 , inf ) ;
int k = 0 ;
for ( int i = 1 ; i <= n ; i ++ ) {
for ( ; k < i ; k ++ )
if ( sum [ i ] - sum [ k ] <= ans1 )
break ;
to [ i ] = k ;
}
for ( int i = 1 ; i <= n ; i ++ )
if ( sum [ i ] <= ans1 )
dp [ 0 ] [ i ] = 1 ;
for ( int i = 1 ; i <= n ; i ++ )
pre [ 0 ] [ i ] = ( pre [ 0 ] [ i - 1 ] + dp [ 0 ] [ i ] ) % mod ;
now = 1 ;
for ( int i = 1 ; i <= m ; i ++ ) {
for ( int j = 1 ; j <= n ; j ++ )
dp [ now ] [ j ] = ( ( pre [ now ^ 1 ] [ j - 1 ] - pre [ now ^ 1 ] [ std :: max ( to [ j ] - 1 , 0 ) ] ) % mod + mod ) % mod ;
for ( int j = 1 ; j <= n ; j ++ )
pre [ now ] [ j ] = ( pre [ now ] [ j - 1 ] + dp [ now ] [ j ] ) % mod ;
ans2 = ( ans2 + dp [ now ] [ n ] ) % mod ;
now ^= 1 ;
}
printf ( "%d %d" , ans1 , ans2 ) ;
return 0 ;
}
/*
3 2
1
1
10
*/