【洛谷】P2511 [HAOI2008]木棍分割

 这题卡常,别用long long 

这题第一问好搞,直接二分答案

第二问,凡是看到求方案数并于组合数一定没有关系的一定用 Dp 解决!

然后定义状态,显然 dp [ i ] [ j ] 表示前 j 个棍棍儿切了 i 刀的方案数

转移就是 dp [ i ] [ j ] = \sum _{k=to[j]}^{j-1}dp[i-1][k]to[j] 是满足条件的第一个点

然后我就不会优化了,看了题解,发现自己思维僵化竟然如此简单

然后可以用前缀和优化

要用滚动数组

// luogu-judger-enable-o2
# include 

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
*/

 

你可能感兴趣的:(dp,杂dp,二分)