题目:有一串数,从里面取出m个不同的区间,每个区间长度不能超过M,使得所取所有数字和最大。
分析:dp,单调队列,区间最大字段和。因为数据都是正的不需要单调队列维护(否则要使用)。
区间最大字段和,求出每个元素作为结束标志的前k项和;取结束位置作为dp状态;
然后,利用单调队列维护区间长度,O(1)时间查找满足长度的最小的前j项和,做差即可。
状态:设f(i,j)为前j个数字,取i个区间最大和;s(j)为前j个数字的最大单区间字段和;
转移:f(i,j)= max(f(i-1,k)+ s(j)) { 其中k ≤ j-M }。
(如果数据可以为负,方程不变,用单调队列计算单区间最大字段和即可)
说明:数据都是正的,可以用更简单的方程dp。。。(2011-11-02 00:16)
#include <stdio.h> #include <stdlib.h> int main() { int F[ 4 ][ 50005 ]; int T,N,M,t,i,m,l,r,s; while ( ~scanf("%d",&T) ) for ( t = 1 ; t <= T ; ++ t ) { scanf("%d",&N); for ( i = 1 ; i <= N ; ++ i ) scanf("%d",&F[ 0 ][ i ]); scanf("%d",&M); for ( s = 0,l = i = 1 ; i <= N ; ++ i ) { s += F[ 0 ][ i ]; if ( i-l >= M ) s -= F[ 0 ][ l ++ ]; F[ 1 ][ i ] = s; } for ( m = 2 ; m <= 3 ; ++ m ) for ( s = 0,i = 1 ; i <= N ; ++ i ) { if ( s < F[ m-1 ][ i-M ] ) s = F[ m-1 ][ i-M ]; F[ m ][ i ] = s + F[ 1 ][ i ]; } int max = 0; for ( i = 1 ; i <= N ; ++ i ) if ( max < F[ 3 ][ i ] ) max = F[ 3 ][ i ]; printf("%d\n",max); } return 0; }
原文地址:http://blog.csdn.net/mobius_strip/article/details/39609007